diff --git a/connectors/lasso/client_params.inc b/connectors/lasso/client_params.inc old mode 100755 new mode 100644 index f77c336a..317147f6 --- a/connectors/lasso/client_params.inc +++ b/connectors/lasso/client_params.inc @@ -1,77 +1,30 @@ -[//lasso - // create a single array of both get and post params - define_tag( - 'params', - -namespace='client_', - -priority='replace', - -description='Returns an array that is a combination of [client_getparams] and [client_postparams].' - ); - local('out') = array; - #out->merge(client_getparams); - #out->merge(client_postparams); - return(#out); - /define_tag; +[//lasso // create a single array of both get and post params +define_tag( 'params', -namespace='client_', -priority='replace', +-description='Returns an array that is a combination of +[client_getparams] and [client_postparams].' ); local('out') = array; +#out->merge(client_getparams); #out->merge(client_postparams); +return(#out); /define_tag; define_tag( 'param', -namespace='client_', +-req='param', -opt='count', -opt='explode', -priority='replace', +-description='Equivalent of [action_param], only for [client_params]. +Safe to use inside inlines.' ); local('out') = string; local('key') = +#param; if(params >> '-count'); #out = client_params->find(#key)->size; - define_tag( - 'param', - -namespace='client_', - -req='param', - -opt='count', - -opt='explode', - -priority='replace', - -description='Equivalent of [action_param], only for [client_params]. Safe to use inside inlines.' - ); - local('out') = string; - local('key') = #param; - - if(params >> '-count'); - #out = client_params->find(#key)->size; - - else(params >> '-explode'); - #out = array; - local('matches') = client_params->find(#key); - - if(#matches->size > 1); - iterate(#matches, local('i')); - #i->isa('pair') ? #out->insert(#i->second) | #out->insert(#i); - /iterate; - - else(#matches->size); - #matches->first->isa('pair') ? #out->insert(#matches->first->second) | #out->insert(#matches->first); - - /if; - - else(params->size >= 2 && params->get(2)->isa('integer')); - local('index') = params->get(2); - - if(client_params->find(#key)->size >= #index); - #out = client_params->find(#key)->get(#index)->second; +else(params >> '-explode'); #out = array; local('matches') = +client_params->find(#key); if(#matches->size > 1); iterate(#matches, +local('i')); #i->isa('pair') ? #out->insert(#i->second) | +#out->insert(#i); /iterate; else(#matches->size); +#matches->first->isa('pair') ? #out->insert(#matches->first->second) | +#out->insert(#matches->first); /if; else(params->size >= 2 && +params->get(2)->isa('integer')); local('index') = params->get(2); - else; - #out = ''; - - /if; - else; - local('matches') = client_params->find(#key); - - if(#matches->size > 1); - iterate(#matches, local('i')); - #out += (#i->isa('pair') ? (#i->second + '\r') | (#i + '\r')); - /iterate; - - else(#matches->size); - #out = (#matches->first->isa('pair') ? #matches->first->second | #matches->first); - - else; - #out = ''; - /if; - - /if; - - return(#out); - /define_tag; +if(client_params->find(#key)->size >= #index); #out = +client_params->find(#key)->get(#index)->second; else; #out = ''; /if; +else; local('matches') = client_params->find(#key); if(#matches->size > +1); iterate(#matches, local('i')); #out += (#i->isa('pair') ? +(#i->second + '\r') | (#i + '\r')); /iterate; else(#matches->size); #out += (#matches->first->isa('pair') ? #matches->first->second | +#matches->first); else; #out = ''; /if; /if; return(#out); /define_tag; - /* SVN $Id: client_params.inc 582 2008-02-21 16:22:11Z Jason Huck $ */ -] +/* SVN $Id: client_params.inc 582 2008-02-21 16:22:11Z Jason Huck $ */ ] diff --git a/connectors/lasso/encode_json.inc b/connectors/lasso/encode_json.inc old mode 100755 new mode 100644 index 245ca8c7..2feb521e --- a/connectors/lasso/encode_json.inc +++ b/connectors/lasso/encode_json.inc @@ -1,410 +1,410 @@ - // - // - // Changes - 2007-06-30 Whitespace between tokens and UTF-8 BOM - // support by Gšran Tšrnquist. 2007-08-07 New map method of - // embedding native data types and -NoNative and -UseNative keywords - // by Fletcher Sandbeck. 2007-09-28 by Fletcher Sandbeck. Added - // [JSON_RPCCall] tag. Added new RPC.LassoApp files which - // automatically recognizes incoming JSON-RPC calls over HTTP. Added - // support for __jsonclass__ embedding method. Added [Object] and - // [Literal] which make JavaScript objects and functions easier to - // define. 2008-11-11 by Fletcher Sandbeck blank values in objects - // will now be set to null, object keys can be specified without - // quotes, arrays of pairs can be created using -UsePairs and decode - // propery. - // - // Installation - Either include this file in the Lasso page you - // want to use these tags or place this file in the "LassoStartup" - // folder within the Lasso Professional 8 application folder or the - // sub-folder for a specific site. - // - // Description - These tags implement simple JSON (JavaScript Object - // Notation) encoding and decoding in Lasso. JSON is a text format - // used for language independent data exchange. It is based on the - // syntax of JavaScript and JSON encoded objects can be passed into - // the JavaScript eval() function directly. - // - // JSON supports the following data types natively: Array, Map, - // String, Integer, Decimal, Boolean, Null, and Date. Every JSON - // object must be wrapped in either an array or a map. If any other - // data type is passed to [Encode_JSON] then it will be encoded as a - // single element array. Literal is a subclass of string which will - // be inserted without quotes or encoding. Object is a subclass of - // map whose keys are embedded as literals. - // - // By default, data type which are not supported natively are - // converted to the closest possible JSON data type. Sets, Lists, - // Queues, etc. are converted to Arrays. - // - // -UseNative can be used to turn off this automatic conversion. If - // -UseNative is specified then each data type is embedded using the - // serialization method described next. - // - // Other data types are embedded using the JSON-RPC standard. - // {"__jsonclass__":["constructor", [param1,...]], "prop1": ...} In - // Lasso, the constructor is always "deserialize" and there is one - // parameter which contains the native Lasso serialization of the - // type. - // - // NOTE - This replaces the Lasso-specific serialization scheme in - // an earlier version of this document. However, the earlier - // serialization scheme will still be decoded for backward - // compatibility with earlier implementations. - // - // -NoNative can be used to turn off embedding data types as a - // __jsonclass__. If -NoNative is specified then data types which - // are not supported natively (and cannot be converted) will be - // skipped. - // - // -UsePairs will insert pairs found in arrays using the member - // notation for objects. An array like ["key": "value"] will be - // generated. This is not technically valid JSON, but will be - // decoded properly by Lasso back into an array of pairs. - // - // [Encode_JSON] - Encodes a Lasso data type as a string. If a map - // or array is passed then it will be encoded directly. Any other - // data type will be wrapped in a single element array and encoded. - // The output will always use UTF-8 encoding without extra escape - // sequences. - // - // [Decode_JSON] - Decodes a JSON object into native Lasso objects. - // The result will be either an array or a map. The tag expects a - // native Lasso string. If you are importing a JSON object encoded - // in UTF-16 or UTF-32 then it should be imported into a Lasso - // string before being decoded. - // - // [JSON_Records] returns the current inline results in a format - // which is compatible with many JavaScript libraries. - // - // [Literal] - This is a subclass of [String]. A literal works - // exactly like a string, but will be inserted directly rather than - // being encoded into JSON. This allows JavaScript elements like - // functions to be inserted into JSON objects. This is most useful - // when the JSON object will be used within a JavaScript on the - // local page. [Map: 'fn'=(Literal: 'function(){ ...})] => {'fn': - // function(){ ...}} - // - // [Object] - This is a subclass of [Map]. An object works exactly - // like a map, but when it is encoded into JSON all of the keys will - // be inserted literally. This makes it easy to create a JavaScript - // object without extraneous quote marks. [Object: 'name'='value'] - // => {name: "value"} - // - // Note - [Object] and [Literal] should only be used when encoding - // Javascript for use in local scripts. They will not generate valid - // JSON encodings. - // - // Feedback - Please let us know if you have any problems with this - // implementation. In particular, please forward us any JSON objects - // which do not decode properly. Send mail to: . - // - // More Information - More information about the JSON standard and - // JSON-RPC can be found at the following URLs. - // - // - // - // - // - +// JSON Encoding and Decoding +// +// Copyright 2007 LassoSoft, LLC +// +// This file was originally published as a Tip of the Week and then +// updated in a subsequent tip of the week. +// +// +// +// +// Changes - 2007-06-30 Whitespace between tokens and UTF-8 BOM +// support by G�ran T�rnquist. 2007-08-07 New map method of +// embedding native data types and -NoNative and -UseNative keywords +// by Fletcher Sandbeck. 2007-09-28 by Fletcher Sandbeck. Added +// [JSON_RPCCall] tag. Added new RPC.LassoApp files which +// automatically recognizes incoming JSON-RPC calls over HTTP. Added +// support for __jsonclass__ embedding method. Added [Object] and +// [Literal] which make JavaScript objects and functions easier to +// define. 2008-11-11 by Fletcher Sandbeck blank values in objects +// will now be set to null, object keys can be specified without +// quotes, arrays of pairs can be created using -UsePairs and decode +// propery. +// +// Installation - Either include this file in the Lasso page you +// want to use these tags or place this file in the "LassoStartup" +// folder within the Lasso Professional 8 application folder or the +// sub-folder for a specific site. +// +// Description - These tags implement simple JSON (JavaScript Object +// Notation) encoding and decoding in Lasso. JSON is a text format +// used for language independent data exchange. It is based on the +// syntax of JavaScript and JSON encoded objects can be passed into +// the JavaScript eval() function directly. +// +// JSON supports the following data types natively: Array, Map, +// String, Integer, Decimal, Boolean, Null, and Date. Every JSON +// object must be wrapped in either an array or a map. If any other +// data type is passed to [Encode_JSON] then it will be encoded as a +// single element array. Literal is a subclass of string which will +// be inserted without quotes or encoding. Object is a subclass of +// map whose keys are embedded as literals. +// +// By default, data type which are not supported natively are +// converted to the closest possible JSON data type. Sets, Lists, +// Queues, etc. are converted to Arrays. +// +// -UseNative can be used to turn off this automatic conversion. If +// -UseNative is specified then each data type is embedded using the +// serialization method described next. +// +// Other data types are embedded using the JSON-RPC standard. +// {"__jsonclass__":["constructor", [param1,...]], "prop1": ...} In +// Lasso, the constructor is always "deserialize" and there is one +// parameter which contains the native Lasso serialization of the +// type. +// +// NOTE - This replaces the Lasso-specific serialization scheme in +// an earlier version of this document. However, the earlier +// serialization scheme will still be decoded for backward +// compatibility with earlier implementations. +// +// -NoNative can be used to turn off embedding data types as a +// __jsonclass__. If -NoNative is specified then data types which +// are not supported natively (and cannot be converted) will be +// skipped. +// +// -UsePairs will insert pairs found in arrays using the member +// notation for objects. An array like ["key": "value"] will be +// generated. This is not technically valid JSON, but will be +// decoded properly by Lasso back into an array of pairs. +// +// [Encode_JSON] - Encodes a Lasso data type as a string. If a map +// or array is passed then it will be encoded directly. Any other +// data type will be wrapped in a single element array and encoded. +// The output will always use UTF-8 encoding without extra escape +// sequences. +// +// [Decode_JSON] - Decodes a JSON object into native Lasso objects. +// The result will be either an array or a map. The tag expects a +// native Lasso string. If you are importing a JSON object encoded +// in UTF-16 or UTF-32 then it should be imported into a Lasso +// string before being decoded. +// +// [JSON_Records] returns the current inline results in a format +// which is compatible with many JavaScript libraries. +// +// [Literal] - This is a subclass of [String]. A literal works +// exactly like a string, but will be inserted directly rather than +// being encoded into JSON. This allows JavaScript elements like +// functions to be inserted into JSON objects. This is most useful +// when the JSON object will be used within a JavaScript on the +// local page. [Map: 'fn'=(Literal: 'function(){ ...})] => {'fn': +// function(){ ...}} +// +// [Object] - This is a subclass of [Map]. An object works exactly +// like a map, but when it is encoded into JSON all of the keys will +// be inserted literally. This makes it easy to create a JavaScript +// object without extraneous quote marks. [Object: 'name'='value'] +// => {name: "value"} +// +// Note - [Object] and [Literal] should only be used when encoding +// Javascript for use in local scripts. They will not generate valid +// JSON encodings. +// +// Feedback - Please let us know if you have any problems with this +// implementation. In particular, please forward us any JSON objects +// which do not decode properly. Send mail to: . +// +// More Information - More information about the JSON standard and +// JSON-RPC can be found at the following URLs. +// +// +// +// +// + // If: (Lasso_TagExists: 'Encode_JSON') == False; - Define_Tag: 'JSON', -Namespace='Encode_', -Required='value', -Optional='options'; - - Local: 'output' = ''; - Local: 'newoptions' = (Array: -Internal); - If: !(Local_Defined: 'options') || (#options->(IsA: 'array') == False); - Local: 'options' = (Array); - /If; - ((#options >> -UseNative) || (Params >> -UseNative)) ? #newoptions->(Insert: -UseNative); - ((#options >> -NoNative) || (Params >> -NoNative)) ? #newoptions->(Insert: -NoNative); - ((#options >> -UsePairs) || (Params >> -UsePairs)) ? #newoptions->(Insert: -UsePairs); - If: (#options !>> -UseNative) && ((#value->(IsA: 'set')) || (#value->(IsA: 'list')) || (#value->(IsA: 'queue')) || (#value->(IsA: 'priorityqueue')) || (#value->(IsA: 'stack'))); - #output += (Encode_JSON: Array->(insertfrom: #value->iterator) &, -Options=#newoptions); - Else: (#options >> -UsePairs) && (#value->(IsA: 'pair')); - #output += (Encode_JSON: #value->First, -Options=#newoptions) + ': ' + (Encode_JSON: #value->Second, -Options=#newoptions); - Else: (#options !>> -UseNative) && (#value->(IsA: 'pair')); - #output += (Encode_JSON: (Array: #value->First, #value->Second), -Options=#newoptions); - Else: (#options !>> -Internal) && (#value->(Isa: 'array') == False) && (#value->(IsA: 'map') == False); - #output += '[' + (Encode_JSON: #value, -Options=#newoptions) + ']'; - Else: (#value->(IsA: 'literal')); - #output += #value; - Else: (#value->(IsA: 'string')); - #output += '"' + ((String: #value)->(Replace: '\"', '\\"') & (Replace: '\r', '\\r') & (Replace: '\n', '\\n') & (Replace: '\t', '\\t') & (Replace: '\f', '\\f') & (Replace: '\b', '\\b') &) + '"'; - Else: (#value->(IsA: 'integer')) || (#value->(IsA: 'decimal')) || (#value->(IsA: 'boolean')); - #output += (String: #value); - Else: (#value->(IsA: 'null')); - #output += 'null'; - Else: (#value->(IsA: 'date')); - if: #value->gmt; - #output += '"' + #value->(format: '%QT%TZ') + '"'; - else; - #output += '"' + #value->(format: '%QT%T') + '"'; - /if; - Else: (#value->(IsA: 'array')); - #output += '['; - Iterate: #value, (Local: 'temp'); - #output += (Encode_JSON: #temp, -Options=#newoptions); - If: #value->Size != Loop_Count; - #output += ', '; - /If; - /Iterate; - #output += ']'; - Else: (#value->(IsA: 'object')); - #output += '{'; - Iterate: #value, (Local: 'temp'); - #output += #temp->First + ': ' + (Encode_JSON: #temp->Second, -Options=#newoptions); - If: (#value->Size != Loop_Count); - #output += ', '; - /If; - /Iterate; - #output += '}'; - Else: (#value->(IsA: 'map')); - #output += '{'; - Iterate: #value, (Local: 'temp'); - #output += (Encode_JSON: #temp->First, -Options=#newoptions) + ': ' + (Encode_JSON: #temp->Second, -Options=#newoptions); - If: (#value->Size != Loop_Count); - #output += ', '; - /If; - /Iterate; - #output += '}'; - Else: (#value->(IsA: 'client_ip')) || (#value->(IsA: 'client_address')); - #output += (Encode_JSON: (String: #value), -Options=#newoptions); - Else: (#options !>> -UseNative) && (#value->(IsA: 'set')) || (#value->(IsA: 'list')) || (#value->(IsA: 'queue')) || (#value->(IsA: 'priorityqueue')) || (#value->(IsA: 'stack')); - #output += (Encode_JSON: Array->(insertfrom: #value->iterator) &, -Options=#newoptions); - Else: (#options !>> -NoNative); - #output += (Encode_JSON: (Map: '__jsonclass__'=(Array:'deserialize',(Array:'' + #value->Serialize + '')))); - /If; - Return: @#output; - - /Define_Tag; +Define_Tag: 'JSON', -Namespace='Encode_', -Required='value', -Optional='options'; + +Local: 'output' = ''; +Local: 'newoptions' = (Array: -Internal); +If: !(Local_Defined: 'options') || (#options->(IsA: 'array') == False); +Local: 'options' = (Array); +/If; +((#options >> -UseNative) || (Params >> -UseNative)) ? #newoptions->(Insert: -UseNative); +((#options >> -NoNative) || (Params >> -NoNative)) ? #newoptions->(Insert: -NoNative); +((#options >> -UsePairs) || (Params >> -UsePairs)) ? #newoptions->(Insert: -UsePairs); +If: (#options !>> -UseNative) && ((#value->(IsA: 'set')) || (#value->(IsA: 'list')) || (#value->(IsA: 'queue')) || (#value->(IsA: 'priorityqueue')) || (#value->(IsA: 'stack'))); +#output += (Encode_JSON: Array->(insertfrom: #value->iterator) &, -Options=#newoptions); +Else: (#options >> -UsePairs) && (#value->(IsA: 'pair')); +#output += (Encode_JSON: #value->First, -Options=#newoptions) + ': ' + (Encode_JSON: #value->Second, -Options=#newoptions); +Else: (#options !>> -UseNative) && (#value->(IsA: 'pair')); +#output += (Encode_JSON: (Array: #value->First, #value->Second), -Options=#newoptions); +Else: (#options !>> -Internal) && (#value->(Isa: 'array') == False) && (#value->(IsA: 'map') == False); +#output += '[' + (Encode_JSON: #value, -Options=#newoptions) + ']'; +Else: (#value->(IsA: 'literal')); +#output += #value; +Else: (#value->(IsA: 'string')); +#output += '"' + ((String: #value)->(Replace: '\"', '\\"') & (Replace: '\r', '\\r') & (Replace: '\n', '\\n') & (Replace: '\t', '\\t') & (Replace: '\f', '\\f') & (Replace: '\b', '\\b') &) + '"'; +Else: (#value->(IsA: 'integer')) || (#value->(IsA: 'decimal')) || (#value->(IsA: 'boolean')); +#output += (String: #value); +Else: (#value->(IsA: 'null')); +#output += 'null'; +Else: (#value->(IsA: 'date')); +if: #value->gmt; +#output += '"' + #value->(format: '%QT%TZ') + '"'; +else; +#output += '"' + #value->(format: '%QT%T') + '"'; +/if; +Else: (#value->(IsA: 'array')); +#output += '['; +Iterate: #value, (Local: 'temp'); +#output += (Encode_JSON: #temp, -Options=#newoptions); +If: #value->Size != Loop_Count; +#output += ', '; +/If; +/Iterate; +#output += ']'; +Else: (#value->(IsA: 'object')); +#output += '{'; +Iterate: #value, (Local: 'temp'); +#output += #temp->First + ': ' + (Encode_JSON: #temp->Second, -Options=#newoptions); +If: (#value->Size != Loop_Count); +#output += ', '; +/If; +/Iterate; +#output += '}'; +Else: (#value->(IsA: 'map')); +#output += '{'; +Iterate: #value, (Local: 'temp'); +#output += (Encode_JSON: #temp->First, -Options=#newoptions) + ': ' + (Encode_JSON: #temp->Second, -Options=#newoptions); +If: (#value->Size != Loop_Count); +#output += ', '; +/If; +/Iterate; +#output += '}'; +Else: (#value->(IsA: 'client_ip')) || (#value->(IsA: 'client_address')); +#output += (Encode_JSON: (String: #value), -Options=#newoptions); +Else: (#options !>> -UseNative) && (#value->(IsA: 'set')) || (#value->(IsA: 'list')) || (#value->(IsA: 'queue')) || (#value->(IsA: 'priorityqueue')) || (#value->(IsA: 'stack')); +#output += (Encode_JSON: Array->(insertfrom: #value->iterator) &, -Options=#newoptions); +Else: (#options !>> -NoNative); +#output += (Encode_JSON: (Map: '__jsonclass__'=(Array:'deserialize',(Array:'' + #value->Serialize + '')))); +/If; +Return: @#output; + +/Define_Tag; // /If; // If: (Lasso_TagExists: 'Decode_JSON') == False; - Define_Tag: 'JSON', -Namespace='Decode_', -Required='value'; +Define_Tag: 'JSON', -Namespace='Decode_', -Required='value'; - (#value == '') ? Return: Null; - - Define_Tag: 'consume_string', -Required='ibytes'; - Local: 'obytes' = bytes; - local: 'temp' = 0; - While: ((#temp := #ibytes->(export8bits: #temp)) != 34); - #obytes->(import8bits: #temp); - (#temp == 92) ? #obytes->(import8bits: #ibytes->export8bits); // Escape \ - /While; - Local: 'output' = ((String: #obytes)->(Replace: '\\"', '\"') & (Replace: '\\r', '\r') & (Replace: '\\n', '\n') & (Replace: '\\t', '\t') & (Replace: '\\f', '\f') & (Replace: '\\b', '\b') &); - If: #output->(BeginsWith: '') && #output->(EndsWith: ''); - Local: 'temp' = #output - '' - ''; - Local: 'output' = null; - Protect; - #output->(Deserialize: #temp); - /Protect; - Else: (Valid_Date: #output, -Format='%QT%TZ'); - Local: 'output' = (Date: #output, -Format='%QT%TZ'); - Else: (Valid_Date: #output, -Format='%QT%T'); - Local: 'output' = (Date: #output, -Format='%QT%T'); - /If; - Return: @#output; - /Define_Tag; - Define_Tag: 'consume_token', -Required='ibytes', -required='temp'; - Local: 'obytes' = bytes->(import8bits: #temp) &; - local: 'delimit' = (array: 9, 10, 13, 32, 44, 58, 93, 125); // \t\r\n ,:]} - While: (#delimit !>> (#temp := #ibytes->export8bits)); - #obytes->(import8bits: #temp); - /While; - Local: 'output' = (String: #obytes); - If: (#output == 'true') || (#output == 'false'); - Return: (Boolean: #output); - Else: (#output == 'null'); - Return: Null; - Else: (String_IsNumeric: #output); - Return: (#output >> '.') ? (Decimal: #output) | (Integer: #output); - /If; - Return: @#output; - /Define_Tag; - Define_Tag: 'consume_key', -Required='ibytes', -required='temp'; - Local: 'obytes' = bytes->(import8bits: #temp) &; - local: 'delimit' = (array: 9, 10, 13, 32, 44, 58, 93, 125); // \t\r\n ,:]} - While: (#delimit !>> (#temp := #ibytes->export8bits)); - #obytes->(import8bits: #temp); - /While; - Local: 'output' = (String: #obytes); - Return: @#output; - /Define_Tag; - Define_Tag: 'consume_array', -Required='ibytes'; - Local: 'output' = array; - local: 'delimit' = (array: 9, 10, 13, 32, 44); // \t\r\n - local: 'temp' = 0; - local: 'pair' = false; - local: 'val' = null; - While: ((#temp := #ibytes->export8bits) != 93); // ] - If: (#delimit >> #temp); - // Discard whitespace - loop_continue; - Else: (#temp == 58); - #pair = true; - loop_continue; - Else: (#temp == 34); // " - #val = (consume_string: @#ibytes); - Else: (#temp == 91); // [ - #val = (consume_array: @#ibytes); - Else: (#temp == 123); // { - #val = (consume_object: @#ibytes); - Else; - #val = (consume_token: @#ibytes, @#temp); - /If; - if(#pair == true); - // Pull last value and re-insert as pair - local: 'key' = #output->last; - #output->remove; - #output->(insert: #key = #val); - else; - #output->(insert: #val); - /if; - #pair = (#temp == 58); // : - (#temp == 93) ? Loop_Abort; // ] - /While; - Return: @#output; - /Define_Tag; - Define_Tag: 'consume_object', -Required='ibytes'; - Local: 'output' = map; - local: 'delimit' = (array: 9, 10, 13, 32); // \t\r\n - local: 'temp' = 0; - local: 'key' = null; - local: 'val' = null; - While: ((#temp := #ibytes->export8bits) != 125); // } - If: (#delimit >> #temp); - // Discard whitespace - loop_continue; - Else: (#key !== null); - If: (#temp == 44); // , - #output->(insert: #key = null); - Else: (#temp == 34); // " - #output->(insert: #key = (consume_string: @#ibytes)); - Else: (#temp == 91); // [ - #output->(insert: #key = (consume_array: @#ibytes)); - Else: (#temp == 123); // { - #output->(insert: #key = (consume_object: @#ibytes)); - Else; - #output->(insert: #key = (consume_token: @#ibytes, @#temp)); - (#temp == 125) ? Loop_abort; // } - /If; - #key = null; - Else: (#temp == 44); // , - // Nothing - Else: (#temp == 34); // " - #key = (consume_string: @#ibytes); - while(#delimit >> (#temp := #ibytes->export8bits)); /while; - #temp != 58 ? Loop_Abort; // : - Else; - #key = (consume_key: @#ibytes, @#temp); - while(#delimit >> #temp); - #temp = #ibytes->export8bits; - /while; - #temp != 58 ? Loop_Abort; // : - /If; - /While; - - If: (#output >> '__jsonclass__') && (#output->(Find: '__jsonclass__')->(isa: 'array')) && (#output->(Find: '__jsonclass__')->size >= 2) && (#output->(Find: '__jsonclass__')->First == 'deserialize'); - Return: #output->(find: '__jsonclass__')->Second->First; - Else: (#output >> 'native') && (#output >> 'comment') && (#output->(find: 'comment') == 'http://www.lassosoft.com/json'); - Return: #output->(find: 'native'); - /If; - Return: @#output; - /Define_Tag; - - Local: 'ibytes' = (bytes: #value); - Local: 'start' = 1; - #ibytes->removeLeading(BOM_UTF8); - Local: 'temp' = #ibytes->export8bits; - If: (#temp == 91); // [ - Local: 'output' = (consume_array: @#ibytes); - Return: @#output; - Else: (#temp == 123); // { - Local: 'output' = (consume_object: @#ibytes); - Return: @#output; - /If; - - /Define_Tag; +(#value == '') ? Return: Null; -// /If; +Define_Tag: 'consume_string', -Required='ibytes'; +Local: 'obytes' = bytes; +local: 'temp' = 0; +While: ((#temp := #ibytes->(export8bits: #temp)) != 34); +#obytes->(import8bits: #temp); +(#temp == 92) ? #obytes->(import8bits: #ibytes->export8bits); // Escape \ +/While; +Local: 'output' = ((String: #obytes)->(Replace: '\\"', '\"') & (Replace: '\\r', '\r') & (Replace: '\\n', '\n') & (Replace: '\\t', '\t') & (Replace: '\\f', '\f') & (Replace: '\\b', '\b') &); +If: #output->(BeginsWith: '') && #output->(EndsWith: ''); +Local: 'temp' = #output - '' - ''; +Local: 'output' = null; +Protect; +#output->(Deserialize: #temp); +/Protect; +Else: (Valid_Date: #output, -Format='%QT%TZ'); +Local: 'output' = (Date: #output, -Format='%QT%TZ'); +Else: (Valid_Date: #output, -Format='%QT%T'); +Local: 'output' = (Date: #output, -Format='%QT%T'); +/If; +Return: @#output; +/Define_Tag; +Define_Tag: 'consume_token', -Required='ibytes', -required='temp'; +Local: 'obytes' = bytes->(import8bits: #temp) &; +local: 'delimit' = (array: 9, 10, 13, 32, 44, 58, 93, 125); // \t\r\n ,:]} +While: (#delimit !>> (#temp := #ibytes->export8bits)); +#obytes->(import8bits: #temp); +/While; +Local: 'output' = (String: #obytes); +If: (#output == 'true') || (#output == 'false'); +Return: (Boolean: #output); +Else: (#output == 'null'); +Return: Null; +Else: (String_IsNumeric: #output); +Return: (#output >> '.') ? (Decimal: #output) | (Integer: #output); +/If; +Return: @#output; +/Define_Tag; +Define_Tag: 'consume_key', -Required='ibytes', -required='temp'; +Local: 'obytes' = bytes->(import8bits: #temp) &; +local: 'delimit' = (array: 9, 10, 13, 32, 44, 58, 93, 125); // \t\r\n ,:]} +While: (#delimit !>> (#temp := #ibytes->export8bits)); +#obytes->(import8bits: #temp); +/While; +Local: 'output' = (String: #obytes); +Return: @#output; +/Define_Tag; +Define_Tag: 'consume_array', -Required='ibytes'; +Local: 'output' = array; +local: 'delimit' = (array: 9, 10, 13, 32, 44); // \t\r\n +local: 'temp' = 0; +local: 'pair' = false; +local: 'val' = null; +While: ((#temp := #ibytes->export8bits) != 93); // ] +If: (#delimit >> #temp); +// Discard whitespace +loop_continue; +Else: (#temp == 58); +#pair = true; +loop_continue; +Else: (#temp == 34); // " +#val = (consume_string: @#ibytes); +Else: (#temp == 91); // [ +#val = (consume_array: @#ibytes); +Else: (#temp == 123); // { +#val = (consume_object: @#ibytes); +Else; +#val = (consume_token: @#ibytes, @#temp); +/If; +if(#pair == true); +// Pull last value and re-insert as pair +local: 'key' = #output->last; +#output->remove; +#output->(insert: #key = #val); +else; +#output->(insert: #val); +/if; +#pair = (#temp == 58); // : +(#temp == 93) ? Loop_Abort; // ] +/While; +Return: @#output; +/Define_Tag; +Define_Tag: 'consume_object', -Required='ibytes'; +Local: 'output' = map; +local: 'delimit' = (array: 9, 10, 13, 32); // \t\r\n +local: 'temp' = 0; +local: 'key' = null; +local: 'val' = null; +While: ((#temp := #ibytes->export8bits) != 125); // } +If: (#delimit >> #temp); +// Discard whitespace +loop_continue; +Else: (#key !== null); +If: (#temp == 44); // , +#output->(insert: #key = null); +Else: (#temp == 34); // " +#output->(insert: #key = (consume_string: @#ibytes)); +Else: (#temp == 91); // [ +#output->(insert: #key = (consume_array: @#ibytes)); +Else: (#temp == 123); // { +#output->(insert: #key = (consume_object: @#ibytes)); +Else; +#output->(insert: #key = (consume_token: @#ibytes, @#temp)); +(#temp == 125) ? Loop_abort; // } +/If; +#key = null; +Else: (#temp == 44); // , +// Nothing +Else: (#temp == 34); // " +#key = (consume_string: @#ibytes); +while(#delimit >> (#temp := #ibytes->export8bits)); /while; +#temp != 58 ? Loop_Abort; // : +Else; +#key = (consume_key: @#ibytes, @#temp); +while(#delimit >> #temp); +#temp = #ibytes->export8bits; +/while; +#temp != 58 ? Loop_Abort; // : +/If; +/While; +If: (#output >> '__jsonclass__') && (#output->(Find: '__jsonclass__')->(isa: 'array')) && (#output->(Find: '__jsonclass__')->size >= 2) && (#output->(Find: '__jsonclass__')->First == 'deserialize'); +Return: #output->(find: '__jsonclass__')->Second->First; +Else: (#output >> 'native') && (#output >> 'comment') && (#output->(find: 'comment') == 'http://www.lassosoft.com/json'); +Return: #output->(find: 'native'); +/If; +Return: @#output; +/Define_Tag; + +Local: 'ibytes' = (bytes: #value); +Local: 'start' = 1; +#ibytes->removeLeading(BOM_UTF8); +Local: 'temp' = #ibytes->export8bits; +If: (#temp == 91); // [ +Local: 'output' = (consume_array: @#ibytes); +Return: @#output; +Else: (#temp == 123); // { +Local: 'output' = (consume_object: @#ibytes); +Return: @#output; +/If; + +/Define_Tag; + +// /If; + // If: (Lasso_TagExists: 'Literal') == False; - Define_Type: 'Literal', 'String'; - /Define_Type; +Define_Type: 'Literal', 'String'; +/Define_Type; // /If; - + // If: (Lasso_TagExists: 'Object') == False; - - Define_Type: 'Object', 'Map'; - /Define_Type; - + +Define_Type: 'Object', 'Map'; +/Define_Type; + // /If; // If: (Lasso_TagExists: 'JSON_RPCCall') == False; - - Define_Tag: 'RPCCall', -Namespace='JSON_', - -Required='method', - -Optional='params', - -Optional='id', - -Optional='host'; - !(Local_Defined: 'host') ? Local: 'host' = 'http://localhost/lassoapps.8/rpc/rpc.lasso'; - !(Local_Defined: 'id') ? Local: 'id' = Lasso_UniqueID; - Local: 'request' = (Map: 'method' = #method, 'params' = #params, 'id' = #id); - Local: 'request' = (Encode_JSON: #request); - - Local: 'result' = (Include_URL: #host, -PostParams=#request); - Local: 'result' = (Decode_JSON: #result); - Return: @#result; - /Define_Tag; - +Define_Tag: 'RPCCall', -Namespace='JSON_', +-Required='method', +-Optional='params', +-Optional='id', +-Optional='host'; +!(Local_Defined: 'host') ? Local: 'host' = 'http://localhost/lassoapps.8/rpc/rpc.lasso'; + +!(Local_Defined: 'id') ? Local: 'id' = Lasso_UniqueID; +Local: 'request' = (Map: 'method' = #method, 'params' = #params, 'id' = #id); +Local: 'request' = (Encode_JSON: #request); + +Local: 'result' = (Include_URL: #host, -PostParams=#request); +Local: 'result' = (Decode_JSON: #result); +Return: @#result; +/Define_Tag; + // /If; // If: (Lasso_TagExists: 'JSON_Records') == False; - Define_Tag: 'JSON_Records', - -Optional='KeyField', - -Optional='ReturnField', - -Optional='ExcludeField', - -Optional='Fields'; - Local: '_fields' = (Local_Defined: 'fields') && #fields->(IsA: 'array') ? #fields | Field_Names; - Fail_If: #_fields->size == 0, -1, 'No fields found for [JSON_Records]'; - Local: '_keyfield' = (Local: 'keyfield'); - If: #_fields !>> #_keyfield; - Local: '_keyfield' = (KeyField_Name); - If: #_fields !>> #_keyfield; - Local: '_keyfield' = 'ID'; - If: #_fields !>> #_keyfield; - Local: '_keyfield' = #_fields->First; - /If; - /If; - /If; - Local: '_index' = #_fields->(FindPosition: #_keyfield)->First; - Local: '_return' = (Local_Defined: 'returnfield') ? (Params->(Find: -ReturnField)->(ForEach: {Params->First = Params->First->Second; Return: True}) &) | @#_fields; - Local: '_exclude' = (Local_Defined: 'excludefield') ? (Params->(Find: -ExcludeField)->(ForEach: {Params->First = Params->First->Second; Return: True}) &) | Array; - Local: '_records' = Array; - Iterate: Records_Array, (Local: '_record'); - Local: '_temp' = Map; - Iterate: #_fields, (Local: '_field'); - ((#_return >> #_field) && (#_exclude !>> #_field)) ? #_temp->Insert(#_field = #_record->(Get: Loop_Count)); - /Iterate; - #_records->Insert(#_temp); - /Iterate; - Local: '_output' = (Encode_JSON: (Object: 'error_msg'=Error_Msg, 'error_code'=Error_Code, 'found_count'=Found_Count, 'keyfield'=#_keyfield, 'rows'=#_records)); - Return: @#_output; - /Define_Tag; +Define_Tag: 'JSON_Records', +-Optional='KeyField', +-Optional='ReturnField', +-Optional='ExcludeField', +-Optional='Fields'; +Local: '_fields' = (Local_Defined: 'fields') && #fields->(IsA: 'array') ? #fields | Field_Names; +Fail_If: #_fields->size == 0, -1, 'No fields found for [JSON_Records]'; +Local: '_keyfield' = (Local: 'keyfield'); +If: #_fields !>> #_keyfield; +Local: '_keyfield' = (KeyField_Name); +If: #_fields !>> #_keyfield; +Local: '_keyfield' = 'ID'; +If: #_fields !>> #_keyfield; +Local: '_keyfield' = #_fields->First; +/If; +/If; +/If; +Local: '_index' = #_fields->(FindPosition: #_keyfield)->First; +Local: '_return' = (Local_Defined: 'returnfield') ? (Params->(Find: -ReturnField)->(ForEach: {Params->First = Params->First->Second; Return: True}) &) | @#_fields; +Local: '_exclude' = (Local_Defined: 'excludefield') ? (Params->(Find: -ExcludeField)->(ForEach: {Params->First = Params->First->Second; Return: True}) &) | Array; +Local: '_records' = Array; +Iterate: Records_Array, (Local: '_record'); +Local: '_temp' = Map; +Iterate: #_fields, (Local: '_field'); +((#_return >> #_field) && (#_exclude !>> #_field)) ? #_temp->Insert(#_field = #_record->(Get: Loop_Count)); +/Iterate; +#_records->Insert(#_temp); +/Iterate; +Local: '_output' = (Encode_JSON: (Object: 'error_msg'=Error_Msg, 'error_code'=Error_Code, 'found_count'=Found_Count, 'keyfield'=#_keyfield, 'rows'=#_records)); +Return: @#_output; +/Define_Tag; // /if; ?> diff --git a/connectors/lasso/encode_urlpath.inc b/connectors/lasso/encode_urlpath.inc old mode 100755 new mode 100644 index 58af0159..4acf958a --- a/connectors/lasso/encode_urlpath.inc +++ b/connectors/lasso/encode_urlpath.inc @@ -1,3 +1 @@ -[//lasso define_tag( 'stricthtml', -namespace='encode_', -required='in', -priority='replace', -description='Encodes all characters in the given string to their HTML equivalents.' ); local('out' = string); iterate(#in, local('i')); #out += '&#' + #i->integer(1) + ';'; /iterate; return(@#out); /define_tag; define_tag( 'urlpath', -namespace='encode_', -required='in', -priority='replace', -description='Makes a string safe to use as a URL path component with Apache.' ); local('out') = #in; #out->replace(' ','_')&replace('/','-!')&replace('\'','`'); #out = encode_stricturl(#out); #out->replace('%5c','\'); return(@#out); /define_tag; define_tag( 'urlpath', -namespace='decode_', -required='in', -priority='replace', -description='Decodes a string encoded by [encode_urlpath].' ); local('out') = #in; #out->replace('_',' ')&replace('\','%5c'); #out = decode_url(#out); #out->replace('-!','/')&replace('`','\''); return(@#out); /define_tag; - - /* SVN $Id: encode_urlpath.inc 210 2006-03-23 20:06:54Z Jason Huck $ */ ] \ No newline at end of file +[//lasso define_tag( 'stricthtml', -namespace='encode_', -required='in', -priority='replace', -description='Encodes all characters in the given string to their HTML equivalents.' ); local('out' = string); iterate(#in, local('i')); #out += '&#' + #i->integer(1) + ';'; /iterate; return(@#out); /define_tag; define_tag( 'urlpath', -namespace='encode_', -required='in', -priority='replace', -description='Makes a string safe to use as a URL path component with Apache.' ); local('out') = #in; #out->replace(' ','_')&replace('/','-!')&replace('\'','`'); #out = encode_stricturl(#out); #out->replace('%5c','\'); return(@#out); /define_tag; define_tag( 'urlpath', -namespace='decode_', -required='in', -priority='replace', -description='Decodes a string encoded by [encode_urlpath].' ); local('out') = #in; #out->replace('_',' ')&replace('\','%5c'); #out = decode_url(#out); #out->replace('-!','/')&replace('`','\''); return(@#out); /define_tag; /* SVN $Id: encode_urlpath.inc 210 2006-03-23 20:06:54Z Jason Huck $ */ ] \ No newline at end of file diff --git a/connectors/lasso/filemanager.inc b/connectors/lasso/filemanager.inc old mode 100755 new mode 100644 index 91875993..c8b7a5ee --- a/connectors/lasso/filemanager.inc +++ b/connectors/lasso/filemanager.inc @@ -1,211 +1,89 @@ -[//lasso - define_type( - 'filemanager', - -prototype, - -description='Replacement for FCKEditor\'s built-in file manager.' - ); - local('fileroot') = '/'; - local('patherror') = encode_json( - map( - 'Error' = 'No permission to operate on specified path.', - 'Code' = -1 - ) - ); - - define_tag('oncreate'); - var_defined('fileroot') ? self->fileroot = $fileroot; - /define_tag; - - define_tag( - 'isvalidpath', - -req='path', - -description='Returns an error if the given path is not within the specified root path.' - ); - return(#path->beginswith(self->fileroot)); - /define_tag; - - define_tag( - 'getinfo', - -req='path', - -opt='getsize', -type='boolean', - -description='Returns a JSON object containing information about the given file.' - ); - !self->isvalidpath(#path) ? return(self->patherror); +[//lasso define_type( 'filemanager', -prototype, +-description='Replacement for FCKEditor\'s built-in file manager.' ); +local('fileroot') = '/'; local('patherror') = encode_json( map( 'Error' += 'No permission to operate on specified path.', 'Code' = -1 ) ); - local('file') = map( - 'Filename' = (#path->endswith('/') ? string(#path)->removetrailing('/')&split('/')->last | #path->split('/')->last), - 'File Type' = '', - 'Preview' = (#path->endswith('/') ? 'images/fileicons/_Open.png' | #path), - 'Path' = #path, - 'Error' = '', - 'Code' = 0, - 'Properties' = map( - 'Date Created' = '', - 'Date Modified' = '', - 'Width' = '', - 'Height' = '', - 'Size' = '' - ) - ); - - local('imagetypes') = set('gif','jpg','jpeg','png'); - - !local_defined('getsize') ? local('getsize') = true; - - if(!file_exists(#path)); - #file->find('Error') = 'File does not exist.'; - #file->find('Code') = file_currenterror( -errorcode); - return(encode_json(#file)); - /if; - - if(#path->endswith('/')); - #file->find('File Type') = 'Directory'; - else; - local('ext') = #path->split('.')->last; - #file->find('File Type') = #ext; - - if(#imagetypes >> #ext && #getsize); - local('img') = image(#path); - #file->find('Properties')->find('Width') = #img->width; - #file->find('Properties')->find('Height') = #img->height; - - else; - local('previewPath') = 'images/fileicons/' + #ext->uppercase& + '.png'; - #file->find('Preview') = (file_exists('../../' + #previewPath) ? #previewPath | 'images/fileicons/default.png'); - /if; - /if; +define_tag('oncreate'); var_defined('fileroot') ? self->fileroot = +$fileroot; /define_tag; define_tag( 'isvalidpath', -req='path', +-description='Returns an error if the given path is not within the +specified root path.' ); return(#path->beginswith(self->fileroot)); +/define_tag; define_tag( 'getinfo', -req='path', -opt='getsize', +-type='boolean', -description='Returns a JSON object containing +information about the given file.' ); !self->isvalidpath(#path) ? +return(self->patherror); local('file') = map( 'Filename' = +(#path->endswith('/') ? +string(#path)->removetrailing('/')&split('/')->last | +#path->split('/')->last), 'File Type' = '', 'Preview' = +(#path->endswith('/') ? 'images/fileicons/_Open.png' | #path), 'Path' = +#path, 'Error' = '', 'Code' = 0, 'Properties' = map( 'Date Created' = +'', 'Date Modified' = '', 'Width' = '', 'Height' = '', 'Size' = '' ) ); - #file->find('Properties')->find('Date Created') = file_creationdate(#path); - #file->find('Properties')->find('Date Modified') = file_moddate(#path); - local('rawsize') = integer(file_getsize(#path)); - #file->find('Properties')->find('Size') = #rawsize; - - return(encode_json(#file)); - /define_tag; +local('imagetypes') = set('gif','jpg','jpeg','png'); - define_tag( - 'getfolder', - -req='path', - -opt='getsizes', -type='boolean' - ); - !self->isvalidpath(#path) ? return(self->patherror); +!local_defined('getsize') ? local('getsize') = true; - local('out') = array; - local('list') = file_listdirectory(#path); - - !local_defined('getsizes') ? local('getsizes') = true; - - iterate(#list, local('i')); - !#i->beginswith('.') ? #out->insert(literal(self->getinfo(#path + #i, -getsize=#getsizes))); - /iterate; - - return(encode_json(#out)); - /define_tag; - - define_tag( - 'rename', - -req='old', - -req='new' - ); - !self->isvalidpath(#old) ? return(self->patherror); +if(!file_exists(#path)); #file->find('Error') = 'File does not exist.'; +#file->find('Code') = file_currenterror( -errorcode); +return(encode_json(#file)); /if; if(#path->endswith('/')); +#file->find('File Type') = 'Directory'; else; local('ext') = +#path->split('.')->last; #file->find('File Type') = #ext; if(#imagetypes +>> #ext && #getsize); local('img') = image(#path); +#file->find('Properties')->find('Width') = #img->width; +#file->find('Properties')->find('Height') = #img->height; else; +local('previewPath') = 'images/fileicons/' + #ext->uppercase& + '.png'; +#file->find('Preview') = (file_exists('../../' + #previewPath) ? +#previewPath | 'images/fileicons/default.png'); /if; /if; - local('oldname') = #old->removetrailing('/')&split('/')->last; - local('path') = string(#old)->removetrailing(#oldname)&; - !#path->endswith('/') ? #path->append('/'); - local('newname') = encode_urlpath(#new); - local('newpath') = #path + #newname; - - file_move(#old, #newpath, -fileoverwrite); - - local('result') = map( - 'Old Path' = #old, - 'Old Name' = #oldname, - 'New Path' = #newpath, - 'New Name' = #newname, - 'Code' = file_currenterror( -errorcode), - 'Error' = file_currenterror - ); - - return(encode_json(#result)); - /define_tag; +#file->find('Properties')->find('Date Created') = +file_creationdate(#path); #file->find('Properties')->find('Date +Modified') = file_moddate(#path); local('rawsize') = +integer(file_getsize(#path)); #file->find('Properties')->find('Size') = +#rawsize; return(encode_json(#file)); /define_tag; define_tag( +'getfolder', -req='path', -opt='getsizes', -type='boolean' ); +!self->isvalidpath(#path) ? return(self->patherror); local('out') = +array; local('list') = file_listdirectory(#path); - define_tag( - 'delete', - -req='path' - ); - !self->isvalidpath(#path) ? return(self->patherror); +!local_defined('getsizes') ? local('getsizes') = true; iterate(#list, +local('i')); !#i->beginswith('.') ? +#out->insert(literal(self->getinfo(#path + #i, -getsize=#getsizes))); +/iterate; return(encode_json(#out)); /define_tag; define_tag( 'rename', +-req='old', -req='new' ); !self->isvalidpath(#old) ? +return(self->patherror); local('oldname') = +#old->removetrailing('/')&split('/')->last; local('path') = +string(#old)->removetrailing(#oldname)&; !#path->endswith('/') ? +#path->append('/'); local('newname') = encode_urlpath(#new); +local('newpath') = #path + #newname; file_move(#old, #newpath, +-fileoverwrite); local('result') = map( 'Old Path' = #old, 'Old Name' = +#oldname, 'New Path' = #newpath, 'New Name' = #newname, 'Code' = +file_currenterror( -errorcode), 'Error' = file_currenterror ); - file_delete(#path); - - local('result') = map( - 'Path' = #path, - 'Error' = file_currenterror, - 'Code' = file_currenterror( -errorcode) - ); - - return(encode_json(#result)); - /define_tag; - - define_tag( - 'add', - -req='path', - -encodenone - ); - !self->isvalidpath(#path) ? return(self->patherror); +return(encode_json(#result)); /define_tag; define_tag( 'delete', +-req='path' ); !self->isvalidpath(#path) ? return(self->patherror); - if(file_uploads->size); - local('upload') = file_uploads->first; - local('newName') = encode_urlpath(#upload->find('origname')); - - file_copy(#upload->find('path'), #path + #newName, -fileoverwrite); +file_delete(#path); local('result') = map( 'Path' = #path, 'Error' = +file_currenterror, 'Code' = file_currenterror( -errorcode) ); - local('result') = map( - 'Path' = #path, - 'Name' = #newName, - 'Error' = file_currenterror, - 'Code' = file_currenterror( -errorcode) - ); - - else; - local('result') = map( - 'Path' = #path, - 'Error' = 'No file was uploaded.', - 'Code' = -1 - ); - /if; - - return(@('')); - /define_tag; - - define_tag( - 'addfolder', - -req='path', - -req='name' - ); - !self->isvalidpath(#path) ? return(self->patherror); +return(encode_json(#result)); /define_tag; define_tag( 'add', +-req='path', -encodenone ); !self->isvalidpath(#path) ? +return(self->patherror); if(file_uploads->size); local('upload') = +file_uploads->first; local('newName') = +encode_urlpath(#upload->find('origname')); - local('newName') = encode_urlpath(#name); - local('newPath') = #path + #newName + '/'; - file_create(#newPath, -fileoverwrite); - - local('result') = map( - 'Parent' = #path, - 'Name' = #newName, - 'Error' = file_currenterror, - 'Code' = file_currenterror( -errorcode) - ); - - return(encode_json(#result)); - /define_tag; - - define_tag( - 'download', - -req='path' - ); - !self->isvalidpath(#path) ? return(self->patherror); - local('name') = #path->split('/')->last; - local('file') = include_raw(#path); - file_serve(#file, #name, -type='application/x-download'); - /define_tag; - /define_type; -] +file_copy(#upload->find('path'), #path + #newName, -fileoverwrite); + +local('result') = map( 'Path' = #path, 'Name' = #newName, 'Error' = +file_currenterror, 'Code' = file_currenterror( -errorcode) ); else; +local('result') = map( 'Path' = #path, 'Error' = 'No file was +uploaded.', 'Code' = -1 ); /if; return(@(' + +')); /define_tag; define_tag( 'addfolder', -req='path', -req='name' ); +!self->isvalidpath(#path) ? return(self->patherror); local('newName') = +encode_urlpath(#name); local('newPath') = #path + #newName + '/'; +file_create(#newPath, -fileoverwrite); local('result') = map( 'Parent' = +#path, 'Name' = #newName, 'Error' = file_currenterror, 'Code' = +file_currenterror( -errorcode) ); return(encode_json(#result)); +/define_tag; define_tag( 'download', -req='path' ); +!self->isvalidpath(#path) ? return(self->patherror); local('name') = +#path->split('/')->last; local('file') = include_raw(#path); +file_serve(#file, #name, -type='application/x-download'); /define_tag; +/define_type; ] diff --git a/connectors/php/filemanager.class.php b/connectors/php/filemanager.class.php index 10c69884..b9e0e59d 100644 --- a/connectors/php/filemanager.class.php +++ b/connectors/php/filemanager.class.php @@ -155,14 +155,14 @@ public function rename() { $suffix=''; - if(substr($this->get['old'],-1,1)=='/') { + if(substr($this->get['old'],-1,1)=='/') { $this->get['old'] = substr($this->get['old'],0,(strlen($this->get['old'])-1)); $suffix='/'; } $tmp = explode('/',$this->get['old']); $filename = $tmp[(sizeof($tmp)-1)]; $path = str_replace('/' . $filename,'',$this->get['old']); - + if(file_exists ($this->doc_root . $path . '/' . $this->get['new'])) { if($suffix=='/' && is_dir($this->doc_root . $path . '/' . $this->get['new'])) { $this->error(sprintf($this->lang('DIRECTORY_ALREADY_EXISTS'),$this->get['new'])); @@ -278,7 +278,7 @@ public function download() { } public function preview() { - + if(isset($this->get['path']) && file_exists($this->doc_root . $this->get['path'])) { header("Content-type: image/" .$ext = pathinfo($this->get['path'], PATHINFO_EXTENSION)); header("Content-Transfer-Encoding: Binary"); diff --git a/connectors/php/filemanager.config.php b/connectors/php/filemanager.config.php index 2c704121..ac5a0e66 100644 --- a/connectors/php/filemanager.config.php +++ b/connectors/php/filemanager.config.php @@ -19,9 +19,9 @@ * @return boolean true is access granted, false if no access */ function auth() { - // You can insert your own code over here to check if the user is authorized. - // If you use a session variable, you've got to start the session first (session_start()) - return true; + // You can insert your own code over here to check if the user is authorized. + // If you use a session variable, you've got to start the session first (session_start()) + return true; } /** diff --git a/connectors/php/filemanager.php b/connectors/php/filemanager.php index e67bfaf2..53379fb6 100644 --- a/connectors/php/filemanager.php +++ b/connectors/php/filemanager.php @@ -19,89 +19,89 @@ $response = ''; if(!auth()) { - $fm->error($fm->lang('AUTHORIZATION_REQUIRED')); + $fm->error($fm->lang('AUTHORIZATION_REQUIRED')); } if(!isset($_GET)) { - $fm->error($fm->lang('INVALID_ACTION')); + $fm->error($fm->lang('INVALID_ACTION')); } else { - - if(isset($_GET['mode']) && $_GET['mode']!='') { - - switch($_GET['mode']) { - - default: - - $fm->error($fm->lang('MODE_ERROR')); - break; - - case 'getinfo': - - if($fm->getvar('path')) { - $response = $fm->getinfo(); - } - break; - - case 'getfolder': - - if($fm->getvar('path')) { - $response = $fm->getfolder(); - } - break; - - case 'rename': - - if($fm->getvar('old') && $fm->getvar('new')) { - $response = $fm->rename(); - } - break; - - case 'delete': - - if($fm->getvar('path')) { - $response = $fm->delete(); - } - break; - - case 'addfolder': - - if($fm->getvar('path') && $fm->getvar('name')) { - $response = $fm->addfolder(); - } - break; - - case 'download': - if($fm->getvar('path')) { - $fm->download(); - } - break; - case 'preview': - if($fm->getvar('path')) { - $fm->preview(); - } - break; - - } - - } else if(isset($_POST['mode']) && $_POST['mode']!='') { - - switch($_POST['mode']) { - - default: - - $fm->error($fm->lang('MODE_ERROR')); - break; - - case 'add': - - if($fm->postvar('currentpath')) { - $fm->add(); - } - break; - - } - - } + + if(isset($_GET['mode']) && $_GET['mode']!='') { + + switch($_GET['mode']) { + + default: + + $fm->error($fm->lang('MODE_ERROR')); + break; + + case 'getinfo': + + if($fm->getvar('path')) { + $response = $fm->getinfo(); + } + break; + + case 'getfolder': + + if($fm->getvar('path')) { + $response = $fm->getfolder(); + } + break; + + case 'rename': + + if($fm->getvar('old') && $fm->getvar('new')) { + $response = $fm->rename(); + } + break; + + case 'delete': + + if($fm->getvar('path')) { + $response = $fm->delete(); + } + break; + + case 'addfolder': + + if($fm->getvar('path') && $fm->getvar('name')) { + $response = $fm->addfolder(); + } + break; + + case 'download': + if($fm->getvar('path')) { + $fm->download(); + } + break; + case 'preview': + if($fm->getvar('path')) { + $fm->preview(); + } + break; + + } + + } else if(isset($_POST['mode']) && $_POST['mode']!='') { + + switch($_POST['mode']) { + + default: + + $fm->error($fm->lang('MODE_ERROR')); + break; + + case 'add': + + if($fm->postvar('currentpath')) { + $fm->add(); + } + break; + + } + + } } echo json_encode($response); diff --git a/connectors/php/inc/JSON.php b/connectors/php/inc/JSON.php index 0cddbddb..4ad29b7f 100644 --- a/connectors/php/inc/JSON.php +++ b/connectors/php/inc/JSON.php @@ -114,693 +114,693 @@ */ class Services_JSON { - /** - * constructs a new JSON instance - * - * @param int $use object behavior flags; combine with boolean-OR - * - * possible values: - * - SERVICES_JSON_LOOSE_TYPE: loose typing. - * "{...}" syntax creates associative arrays - * instead of objects in decode(). - * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. - * Values which can't be encoded (e.g. resources) - * appear as NULL instead of throwing errors. - * By default, a deeply-nested resource will - * bubble up with an error, so all return values - * from encode() should be checked with isError() - */ - function Services_JSON($use = 0) - { - $this->use = $use; + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); } - /** - * convert a string from one UTF-16 char to one UTF-8 char - * - * Normally should be handled by mb_convert_encoding, but - * provides a slower PHP-only method for installations - * that lack the multibye string extension. - * - * @param string $utf16 UTF-16 character - * @return string UTF-8 character - * @access private - */ - function utf162utf8($utf16) - { - // oh please oh please oh please oh please oh please - if(function_exists('mb_convert_encoding')) { - return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } } - $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); - - switch(true) { - case ((0x7F & $bytes) == $bytes): - // this case should never be reached, because we are in ASCII range - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0x7F & $bytes); - - case (0x07FF & $bytes) == $bytes: - // return a 2-byte UTF-8 character - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0xC0 | (($bytes >> 6) & 0x1F)) - . chr(0x80 | ($bytes & 0x3F)); - - case (0xFFFF & $bytes) == $bytes: - // return a 3-byte UTF-8 character - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0xE0 | (($bytes >> 12) & 0x0F)) - . chr(0x80 | (($bytes >> 6) & 0x3F)) - . chr(0x80 | ($bytes & 0x3F)); + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; } - // ignoring UTF-32 for now, sorry - return ''; - } + // treat it like a regular array + $elements = array_map(array($this, 'encode'), $var); - /** - * convert a string from one UTF-8 char to one UTF-16 char - * - * Normally should be handled by mb_convert_encoding, but - * provides a slower PHP-only method for installations - * that lack the multibye string extension. - * - * @param string $utf8 UTF-8 character - * @return string UTF-16 character - * @access private - */ - function utf82utf16($utf8) - { - // oh please oh please oh please oh please oh please - if(function_exists('mb_convert_encoding')) { - return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + foreach($elements as $element) { + if(Services_JSON::isError($element)) { + return $element; + } } - switch(strlen($utf8)) { - case 1: - // this case should never be reached, because we are in ASCII range - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return $utf8; - - case 2: - // return a UTF-16 character from a 2-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0x07 & (ord($utf8{0}) >> 2)) - . chr((0xC0 & (ord($utf8{0}) << 6)) - | (0x3F & ord($utf8{1}))); - - case 3: - // return a UTF-16 character from a 3-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr((0xF0 & (ord($utf8{0}) << 4)) - | (0x0F & (ord($utf8{1}) >> 2))) - . chr((0xC0 & (ord($utf8{1}) << 6)) - | (0x7F & ord($utf8{2}))); + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } } - // ignoring UTF-32 for now, sorry - return ''; + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->encode($value); + + if(Services_JSON::isError($encoded_value)) { + return $encoded_value; } - /** - * encodes an arbitrary variable into JSON format - * - * @param mixed $var any number, boolean, string, array, or object to be encoded. - * see argument 1 to Services_JSON() above for array-parsing behavior. - * if var is a strng, note that encode() always expects it - * to be in ASCII or UTF-8 format! - * - * @return mixed JSON string representation of input var or an error if a problem occurs - * @access public - */ - function encode($var) - { - switch (gettype($var)) { - case 'boolean': - return $var ? 'true' : 'false'; - - case 'NULL': - return 'null'; - - case 'integer': - return (int) $var; - - case 'double': - case 'float': - return (float) $var; - - case 'string': - // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT - $ascii = ''; - $strlen_var = strlen($var); - - /* - * Iterate over every character in the string, - * escaping with a slash or encoding to UTF-8 where necessary - */ - for ($c = 0; $c < $strlen_var; ++$c) { - - $ord_var_c = ord($var{$c}); - - switch (true) { - case $ord_var_c == 0x08: - $ascii .= '\b'; - break; - case $ord_var_c == 0x09: - $ascii .= '\t'; - break; - case $ord_var_c == 0x0A: - $ascii .= '\n'; - break; - case $ord_var_c == 0x0C: - $ascii .= '\f'; - break; - case $ord_var_c == 0x0D: - $ascii .= '\r'; - break; - - case $ord_var_c == 0x22: - case $ord_var_c == 0x2F: - case $ord_var_c == 0x5C: - // double quote, slash, slosh - $ascii .= '\\'.$var{$c}; - break; - - case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): - // characters U-00000000 - U-0000007F (same as ASCII) - $ascii .= $var{$c}; - break; - - case (($ord_var_c & 0xE0) == 0xC0): - // characters U-00000080 - U-000007FF, mask 110XXXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, ord($var{$c + 1})); - $c += 1; - $utf16 = $this->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF0) == 0xE0): - // characters U-00000800 - U-0000FFFF, mask 1110XXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2})); - $c += 2; - $utf16 = $this->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF8) == 0xF0): - // characters U-00010000 - U-001FFFFF, mask 11110XXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3})); - $c += 3; - $utf16 = $this->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFC) == 0xF8): - // characters U-00200000 - U-03FFFFFF, mask 111110XX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4})); - $c += 4; - $utf16 = $this->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFE) == 0xFC): - // characters U-04000000 - U-7FFFFFFF, mask 1111110X - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4}), - ord($var{$c + 5})); - $c += 5; - $utf16 = $this->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - } - } + return $this->encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', - return '"'.$ascii.'"'; - - case 'array': - /* - * As per JSON spec if any array key is not an integer - * we must treat the the whole array as an object. We - * also try to catch a sparsely populated associative - * array with numeric keys here because some JS engines - * will create an array with empty indexes up to - * max_index which can cause memory issues and because - * the keys, which may be relevant, will be remapped - * otherwise. - * - * As per the ECMA and JSON specification an object may - * have any string as a property. Unfortunately due to - * a hole in the ECMA specification if the key is a - * ECMA reserved word or starts with a digit the - * parameter is only accessible using ECMAScript's - * bracket notation. - */ - - // treat as a JSON object - if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { - $properties = array_map(array($this, 'name_value'), - array_keys($var), - array_values($var)); - - foreach($properties as $property) { - if(Services_JSON::isError($property)) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - } + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' - // treat it like a regular array - $elements = array_map(array($this, 'encode'), $var); + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; - foreach($elements as $element) { - if(Services_JSON::isError($element)) { - return $element; - } + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); - return '[' . join(',', $elements) . ']'; + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } - case 'object': - $vars = get_object_vars($var); + } - $properties = array_map(array($this, 'name_value'), - array_keys($vars), - array_values($vars)); + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); - foreach($properties as $property) { - if(Services_JSON::isError($property)) { - return $property; - } - } + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); - return '{' . join(',', $properties) . '}'; + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); - default: - return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) - ? 'null' - : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); - } - } + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - /** - * array-walking function for use in generating JSON-formatted name-value pairs - * - * @param string $name name of key to use - * @param mixed $value reference to an array element to be encoded - * - * @return string JSON-formatted name-value pair, like '"name":value' - * @access private - */ - function name_value($name, $value) - { - $encoded_value = $this->encode($value); + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); - if(Services_JSON::isError($encoded_value)) { - return $encoded_value; - } + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - return $this->encode(strval($name)) . ':' . $encoded_value; - } + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); - /** - * reduce a string by removing leading and trailing comments and whitespace - * - * @param $str string string value to strip of comments and whitespace - * - * @return string string value stripped of comments and whitespace - * @access private - */ - function reduce_string($str) - { - $str = preg_replace(array( + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; - // eliminate single line comments in '// ...' form - '#^\s*//(.+)$#m', + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); - // eliminate multi-line comments in '/* ... */' form, at start of string - '#^\s*/\*(.+)\*/#Us', + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - // eliminate multi-line comments in '/* ... */' form, at end of string - '#/\*(.+)\*/\s*$#Us' + } - ), '', $str); + } - // eliminate extraneous space - return trim($str); - } + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; - /** - * decodes a JSON string into appropriate variable - * - * @param string $str JSON-formatted string - * - * @return mixed number, boolean, string, array, or object - * corresponding to given JSON input string. - * See argument 1 to Services_JSON() above for object-output behavior. - * Note that decode() always returns strings - * in ASCII or UTF-8 format! - * @access public - */ - function decode($str) - { - $str = $this->reduce_string($str); - - switch (strtolower($str)) { - case 'true': - return true; - - case 'false': - return false; - - case 'null': - return null; - - default: - $m = array(); - - if (is_numeric($str)) { - // Lookie-loo, it's a number - - // This would work on its own, but I'm trying to be - // good about returning integers where appropriate: - // return (float)$str; - - // Return float or int, as appropriate - return ((float)$str == (integer)$str) - ? (integer)$str - : (float)$str; - - } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { - // STRINGS RETURNED IN UTF-8 FORMAT - $delim = substr($str, 0, 1); - $chrs = substr($str, 1, -1); - $utf8 = ''; - $strlen_chrs = strlen($chrs); - - for ($c = 0; $c < $strlen_chrs; ++$c) { - - $substr_chrs_c_2 = substr($chrs, $c, 2); - $ord_chrs_c = ord($chrs{$c}); - - switch (true) { - case $substr_chrs_c_2 == '\b': - $utf8 .= chr(0x08); - ++$c; - break; - case $substr_chrs_c_2 == '\t': - $utf8 .= chr(0x09); - ++$c; - break; - case $substr_chrs_c_2 == '\n': - $utf8 .= chr(0x0A); - ++$c; - break; - case $substr_chrs_c_2 == '\f': - $utf8 .= chr(0x0C); - ++$c; - break; - case $substr_chrs_c_2 == '\r': - $utf8 .= chr(0x0D); - ++$c; - break; - - case $substr_chrs_c_2 == '\\"': - case $substr_chrs_c_2 == '\\\'': - case $substr_chrs_c_2 == '\\\\': - case $substr_chrs_c_2 == '\\/': - if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || - ($delim == "'" && $substr_chrs_c_2 != '\\"')) { - $utf8 .= $chrs{++$c}; - } - break; - - case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): - // single, escaped unicode character - $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) - . chr(hexdec(substr($chrs, ($c + 4), 2))); - $utf8 .= $this->utf162utf8($utf16); - $c += 5; - break; - - case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): - $utf8 .= $chrs{$c}; - break; - - case ($ord_chrs_c & 0xE0) == 0xC0: - // characters U-00000080 - U-000007FF, mask 110XXXXX - //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 2); - ++$c; - break; - - case ($ord_chrs_c & 0xF0) == 0xE0: - // characters U-00000800 - U-0000FFFF, mask 1110XXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 3); - $c += 2; - break; - - case ($ord_chrs_c & 0xF8) == 0xF0: - // characters U-00010000 - U-001FFFFF, mask 11110XXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 4); - $c += 3; - break; - - case ($ord_chrs_c & 0xFC) == 0xF8: - // characters U-00200000 - U-03FFFFFF, mask 111110XX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 5); - $c += 4; - break; - - case ($ord_chrs_c & 0xFE) == 0xFC: - // characters U-04000000 - U-7FFFFFFF, mask 1111110X - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 6); - $c += 5; - break; - - } - - } - - return $utf8; - - } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { - // array, or object notation - - if ($str{0} == '[') { - $stk = array(SERVICES_JSON_IN_ARR); - $arr = array(); - } else { - if ($this->use & SERVICES_JSON_LOOSE_TYPE) { - $stk = array(SERVICES_JSON_IN_OBJ); - $obj = array(); - } else { - $stk = array(SERVICES_JSON_IN_OBJ); - $obj = new stdClass(); - } - } - - array_push($stk, array('what' => SERVICES_JSON_SLICE, - 'where' => 0, - 'delim' => false)); + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; - $chrs = substr($str, 1, -1); - $chrs = $this->reduce_string($chrs); - - if ($chrs == '') { - if (reset($stk) == SERVICES_JSON_IN_ARR) { - return $arr; - - } else { - return $obj; - - } - } - - //print("\nparsing {$chrs}\n"); - - $strlen_chrs = strlen($chrs); - - for ($c = 0; $c <= $strlen_chrs; ++$c) { - - $top = end($stk); - $substr_chrs_c_2 = substr($chrs, $c, 2); - - if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { - // found a comma that is not inside a string, array, etc., - // OR we've reached the end of the character list - $slice = substr($chrs, $top['where'], ($c - $top['where'])); - array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); - //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - if (reset($stk) == SERVICES_JSON_IN_ARR) { - // we are in an array, so just push an element onto the stack - array_push($arr, $this->decode($slice)); - - } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { - // we are in an object, so figure - // out the property name and set an - // element in an associative array, - // for now - $parts = array(); - - if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { - // "name":value pair - $key = $this->decode($parts[1]); - $val = $this->decode($parts[2]); - - if ($this->use & SERVICES_JSON_LOOSE_TYPE) { - $obj[$key] = $val; - } else { - $obj->$key = $val; - } - } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { - // name:value pair, where name is unquoted - $key = $parts[1]; - $val = $this->decode($parts[2]); - - if ($this->use & SERVICES_JSON_LOOSE_TYPE) { - $obj[$key] = $val; - } else { - $obj->$key = $val; - } - } - - } - - } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { - // found a quote, and we are not inside a string - array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); - //print("Found start of string at {$c}\n"); - - } elseif (($chrs{$c} == $top['delim']) && - ($top['what'] == SERVICES_JSON_IN_STR) && - ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { - // found a quote, we're in a string, and it's not escaped - // we know that it's not escaped becase there is _not_ an - // odd number of backslashes at the end of the string so far - array_pop($stk); - //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); - - } elseif (($chrs{$c} == '[') && - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { - // found a left-bracket, and we are in an array, object, or slice - array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); - //print("Found start of array at {$c}\n"); - - } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { - // found a right-bracket, and we're in an array - array_pop($stk); - //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - } elseif (($chrs{$c} == '{') && - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { - // found a left-brace, and we are in an array, object, or slice - array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); - //print("Found start of object at {$c}\n"); - - } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { - // found a right-brace, and we're in an object - array_pop($stk); - //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - } elseif (($substr_chrs_c_2 == '/*') && - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { - // found a comment start, and we are in an array, object, or slice - array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); - $c++; - //print("Found start of comment at {$c}\n"); - - } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { - // found a comment end, and we're in one now - array_pop($stk); - $c++; - - for ($i = $top['where']; $i <= $c; ++$i) - $chrs = substr_replace($chrs, ' ', $i, 1); - - //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - } - - } - - if (reset($stk) == SERVICES_JSON_IN_ARR) { - return $arr; - - } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { - return $obj; - - } + } - } } } - - /** - * @todo Ultimately, this should just call PEAR::isError() - */ - function isError($data, $code = null) - { - if (class_exists('pear')) { - return PEAR::isError($data, $code); - } elseif (is_object($data) && (get_class($data) == 'services_json_error' || - is_subclass_of($data, 'services_json_error'))) { - return true; - } - - return false; + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; } + + return false; + } } if (class_exists('PEAR_Error')) { - class Services_JSON_Error extends PEAR_Error + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) { - function Services_JSON_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) - { - parent::PEAR_Error($message, $code, $mode, $options, $userinfo); - } + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); } + } } else { - /** - * @todo Ultimately, this class shall be descended from PEAR_Error - */ - class Services_JSON_Error + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) { - function Services_JSON_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) - { - } } + } } - + ?> diff --git a/index.html b/index.html old mode 100755 new mode 100644 index 5dea8840..b50c2a27 --- a/index.html +++ b/index.html @@ -1,49 +1,55 @@ - - - File Manager - - - - - - - -
-
-

-
- - - - - - -
-
-
-

-
+ + + +
+
+

+
+ + + + + +
+
+
+
+

+
+
-
    -
  • -
  • -
  • -
  • -
+
    +
  • +
  • +
  • +
  • +
- - - - - - - - - -
- + + + + + +
+ \ No newline at end of file diff --git a/scripts/filemanager.config.js.default b/scripts/filemanager.config.js.default index 1f642b5b..75ad9189 100644 --- a/scripts/filemanager.config.js.default +++ b/scripts/filemanager.config.js.default @@ -8,6 +8,9 @@ var culture = 'en'; // Autoload text in GUI var autoload = true; +// Display full path - default : false +var showFullPath = false; + // Set this to the server side language you wish to use. var lang = 'php'; // options: php, jsp // we are looking for contributors for lasso, python connectors (partially developed) diff --git a/scripts/filemanager.js b/scripts/filemanager.js index 4c461aef..56b911d2 100644 --- a/scripts/filemanager.js +++ b/scripts/filemanager.js @@ -1,3 +1,14 @@ +/** + * Filemanager JS core + * + * filemanager.js + * + * @license MIT License + * @author Jason Huck - Core Five Labs + * @author Simon Georget + * @copyright Authors + */ + // function to retrieve GET params $.urlParam = function(name){ var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); @@ -59,8 +70,11 @@ var setDimensions = function(){ } // Display Min Path -var disp = function(path){ - return path.replace(fileRoot, "/"); +var displayRoot = function(path){ + if(showFullPath == false) + return path.replace(fileRoot, "/"); + else + return path; } // from http://phpjs.org/functions/basename:360 @@ -79,7 +93,7 @@ var basename = function(path, suffix) { // whenever a new directory is selected. var setUploader = function(path){ $('#currentpath').val(path); - $('#uploader h1').text(lg.current_folder + disp(path)); + $('#uploader h1').text(lg.current_folder + displayRoot(path)); $('#newfolder').unbind().click(function(){ var foldername = lg.default_foldername; @@ -381,10 +395,10 @@ var removeNode = function(path){ var addFolder = function(parent, name){ var newNode = ''; var parentNode = $('#filetree').find('a[rel="' + parent + '"]'); - if(parent != fileRoot){ parentNode.next('ul').prepend(newNode).prev('a').click().click(); } else { + // todo : Reload filetree $('#filetree > ul').append(newNode); } diff --git a/scripts/jquery.contextmenu/jquery.contextMenu.css b/scripts/jquery.contextmenu/jquery.contextMenu.css old mode 100755 new mode 100644 index cc670018..2e26f5c2 --- a/scripts/jquery.contextmenu/jquery.contextMenu.css +++ b/scripts/jquery.contextmenu/jquery.contextMenu.css @@ -53,10 +53,26 @@ You can add icons to the context menu by adding classes to the respective LI element(s) */ +.contextMenu LI.edit A { + background-image: url(images/page_white_edit.png); +} + +.contextMenu LI.cut A { + background-image: url(images/cut.png); +} + +.contextMenu LI.copy A { + background-image: url(images/page_white_copy.png); +} + +.contextMenu LI.paste A { + background-image: url(images/page_white_paste.png); +} + +.contextMenu LI.delete A { + background-image: url(images/page_white_delete.png); +} -.contextMenu LI.edit A { background-image: url(images/page_white_edit.png); } -.contextMenu LI.cut A { background-image: url(images/cut.png); } -.contextMenu LI.copy A { background-image: url(images/page_white_copy.png); } -.contextMenu LI.paste A { background-image: url(images/page_white_paste.png); } -.contextMenu LI.delete A { background-image: url(images/page_white_delete.png); } -.contextMenu LI.quit A { background-image: url(images/door.png); } +.contextMenu LI.quit A { + background-image: url(images/door.png); +} \ No newline at end of file diff --git a/scripts/jquery.contextmenu/jqueryContextMenu.html b/scripts/jquery.contextmenu/jqueryContextMenu.html old mode 100755 new mode 100644 index 1c8368a6..8f5128c3 --- a/scripts/jquery.contextmenu/jqueryContextMenu.html +++ b/scripts/jquery.contextmenu/jqueryContextMenu.html @@ -2,81 +2,81 @@ - - jQuery Context Menu Plugin Demo - - - - - - - - - + + + + - - - - -

jQuery Context Menu Plugin Demo

-

- This plugin lets you add context menu functionality to your web applications. -

- -

- Tip: Try using your keyboard to make a selection. -

- -

- Back to the project page -

- -

Demo

- -
- Right click for the standard context menu -
- -
-
    -
  • Item 1
  • -
  • Item 2
  • -
  • Item 3
  • -
  • Item 4
  • -
  • Item 5
  • -
  • Item 6
  • -
-
- -
-

- - -

- -

- - -

-
- - - - + + + + +

jQuery Context Menu Plugin Demo

+

This plugin lets you add context menu functionality to your web +applications.

+ +

Tip: Try using your keyboard to make a +selection.

+ +

Back to the project page

+ +

Demo

+ +
Right click for the standard context menu
+ +
+
    +
  • Item 1
  • +
  • Item 2
  • +
  • Item 3
  • +
  • Item 4
  • +
  • Item 5
  • +
  • Item 6
  • +
+
+ +
+

+

+ +

+
+ + + + \ No newline at end of file diff --git a/scripts/jquery.filetree/connectors/jqueryFileTree.php b/scripts/jquery.filetree/connectors/jqueryFileTree.php index 26af7bbb..b1f02553 100644 --- a/scripts/jquery.filetree/connectors/jqueryFileTree.php +++ b/scripts/jquery.filetree/connectors/jqueryFileTree.php @@ -24,28 +24,28 @@ // Check if user is authorized if(auth()) { - -if( file_exists($path) ) { - $files = scandir($path); - natcasesort($files); - if( count($files) > 2 ) { /* The 2 accounts for . and .. */ - echo "
    "; - // All dirs - foreach( $files as $file ) { - if( file_exists($path . $file) && !in_array($file, $config['unallowed_dirs']) && $file != '.' && $file != '..' && is_dir($root . $_POST['dir'] . $file) ) { - echo "
  • " . htmlentities($file) . "
  • "; - } - } - // All files - foreach( $files as $file ) { - if( file_exists($path . $file) && !in_array($file, $config['unallowed_files']) && $file != '.' && $file != '..' && !is_dir($root . $_POST['dir'] . $file) ) { - $ext = preg_replace('/^.*\./', '', $file); - echo "
  • " . htmlentities($file) . "
  • "; - } - } - echo "
"; - } -} + + if( file_exists($path) ) { + $files = scandir($path); + natcasesort($files); + if( count($files) > 2 ) { /* The 2 accounts for . and .. */ + echo "
    "; + // All dirs + foreach( $files as $file ) { + if( file_exists($path . $file) && !in_array($file, $config['unallowed_dirs']) && $file != '.' && $file != '..' && is_dir($root . $_POST['dir'] . $file) ) { + echo "
  • " . htmlentities($file) . "
  • "; + } + } + // All files + foreach( $files as $file ) { + if( file_exists($path . $file) && !in_array($file, $config['unallowed_files']) && $file != '.' && $file != '..' && !is_dir($root . $_POST['dir'] . $file) ) { + $ext = preg_replace('/^.*\./', '', $file); + echo "
  • " . htmlentities($file) . "
  • "; + } + } + echo "
"; + } + } } diff --git a/scripts/jquery.filetree/jqueryFileTree.css b/scripts/jquery.filetree/jqueryFileTree.css old mode 100755 new mode 100644 index 32bf087d..9f8cfc62 --- a/scripts/jquery.filetree/jqueryFileTree.css +++ b/scripts/jquery.filetree/jqueryFileTree.css @@ -26,66 +26,251 @@ UL.jqueryFileTree A:hover { } /* Core Styles */ -.jqueryFileTree LI.directory { background: url(images/directory.png) left top no-repeat; } -.jqueryFileTree LI.expanded { background: url(images/folder_open.png) left top no-repeat; } -.jqueryFileTree LI.file { background: url(images/file.png) left top no-repeat; } -.jqueryFileTree LI.wait { background: url(images/spinner.gif) left top no-repeat; } +.jqueryFileTree LI.directory { + background: url(images/directory.png) left top no-repeat; +} + +.jqueryFileTree LI.expanded { + background: url(images/folder_open.png) left top no-repeat; +} + +.jqueryFileTree LI.file { + background: url(images/file.png) left top no-repeat; +} + +.jqueryFileTree LI.wait { + background: url(images/spinner.gif) left top no-repeat; +} + /* File Extensions*/ -.jqueryFileTree LI.ext_3gp { background: url(images/film.png) left top no-repeat; } -.jqueryFileTree LI.ext_afp { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_afpa { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_asp { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_aspx { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_avi { background: url(images/film.png) left top no-repeat; } -.jqueryFileTree LI.ext_bat { background: url(images/application.png) left top no-repeat; } -.jqueryFileTree LI.ext_bmp { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_c { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_cfm { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_cgi { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_com { background: url(images/application.png) left top no-repeat; } -.jqueryFileTree LI.ext_cpp { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_css { background: url(images/css.png) left top no-repeat; } -.jqueryFileTree LI.ext_doc { background: url(images/doc.png) left top no-repeat; } -.jqueryFileTree LI.ext_exe { background: url(images/application.png) left top no-repeat; } -.jqueryFileTree LI.ext_gif { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_fla { background: url(images/flash.png) left top no-repeat; } -.jqueryFileTree LI.ext_h { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_htm { background: url(images/html.png) left top no-repeat; } -.jqueryFileTree LI.ext_html { background: url(images/html.png) left top no-repeat; } -.jqueryFileTree LI.ext_jar { background: url(images/java.png) left top no-repeat; } -.jqueryFileTree LI.ext_jpg { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_jpeg { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_js { background: url(images/script.png) left top no-repeat; } -.jqueryFileTree LI.ext_lasso { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_log { background: url(images/txt.png) left top no-repeat; } -.jqueryFileTree LI.ext_m4p { background: url(images/music.png) left top no-repeat; } -.jqueryFileTree LI.ext_mov { background: url(images/film.png) left top no-repeat; } -.jqueryFileTree LI.ext_mp3 { background: url(images/music.png) left top no-repeat; } -.jqueryFileTree LI.ext_mp4 { background: url(images/film.png) left top no-repeat; } -.jqueryFileTree LI.ext_mpg { background: url(images/film.png) left top no-repeat; } -.jqueryFileTree LI.ext_mpeg { background: url(images/film.png) left top no-repeat; } -.jqueryFileTree LI.ext_ogg { background: url(images/music.png) left top no-repeat; } -.jqueryFileTree LI.ext_pcx { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_pdf { background: url(images/pdf.png) left top no-repeat; } -.jqueryFileTree LI.ext_php { background: url(images/php.png) left top no-repeat; } -.jqueryFileTree LI.ext_png { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_ppt { background: url(images/ppt.png) left top no-repeat; } -.jqueryFileTree LI.ext_psd { background: url(images/psd.png) left top no-repeat; } -.jqueryFileTree LI.ext_pl { background: url(images/script.png) left top no-repeat; } -.jqueryFileTree LI.ext_py { background: url(images/script.png) left top no-repeat; } -.jqueryFileTree LI.ext_rb { background: url(images/ruby.png) left top no-repeat; } -.jqueryFileTree LI.ext_rbx { background: url(images/ruby.png) left top no-repeat; } -.jqueryFileTree LI.ext_rhtml { background: url(images/ruby.png) left top no-repeat; } -.jqueryFileTree LI.ext_rpm { background: url(images/linux.png) left top no-repeat; } -.jqueryFileTree LI.ext_ruby { background: url(images/ruby.png) left top no-repeat; } -.jqueryFileTree LI.ext_sql { background: url(images/db.png) left top no-repeat; } -.jqueryFileTree LI.ext_swf { background: url(images/flash.png) left top no-repeat; } -.jqueryFileTree LI.ext_tif { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_tiff { background: url(images/picture.png) left top no-repeat; } -.jqueryFileTree LI.ext_txt { background: url(images/txt.png) left top no-repeat; } -.jqueryFileTree LI.ext_vb { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_wav { background: url(images/music.png) left top no-repeat; } -.jqueryFileTree LI.ext_wmv { background: url(images/film.png) left top no-repeat; } -.jqueryFileTree LI.ext_xls { background: url(images/xls.png) left top no-repeat; } -.jqueryFileTree LI.ext_xml { background: url(images/code.png) left top no-repeat; } -.jqueryFileTree LI.ext_zip { background: url(images/zip.png) left top no-repeat; } \ No newline at end of file +.jqueryFileTree LI.ext_3gp { + background: url(images/film.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_afp { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_afpa { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_asp { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_aspx { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_avi { + background: url(images/film.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_bat { + background: url(images/application.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_bmp { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_c { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_cfm { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_cgi { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_com { + background: url(images/application.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_cpp { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_css { + background: url(images/css.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_doc { + background: url(images/doc.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_exe { + background: url(images/application.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_gif { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_fla { + background: url(images/flash.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_h { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_htm { + background: url(images/html.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_html { + background: url(images/html.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_jar { + background: url(images/java.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_jpg { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_jpeg { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_js { + background: url(images/script.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_lasso { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_log { + background: url(images/txt.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_m4p { + background: url(images/music.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_mov { + background: url(images/film.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_mp3 { + background: url(images/music.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_mp4 { + background: url(images/film.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_mpg { + background: url(images/film.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_mpeg { + background: url(images/film.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_ogg { + background: url(images/music.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_pcx { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_pdf { + background: url(images/pdf.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_php { + background: url(images/php.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_png { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_ppt { + background: url(images/ppt.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_psd { + background: url(images/psd.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_pl { + background: url(images/script.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_py { + background: url(images/script.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_rb { + background: url(images/ruby.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_rbx { + background: url(images/ruby.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_rhtml { + background: url(images/ruby.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_rpm { + background: url(images/linux.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_ruby { + background: url(images/ruby.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_sql { + background: url(images/db.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_swf { + background: url(images/flash.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_tif { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_tiff { + background: url(images/picture.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_txt { + background: url(images/txt.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_vb { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_wav { + background: url(images/music.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_wmv { + background: url(images/film.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_xls { + background: url(images/xls.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_xml { + background: url(images/code.png) left top no-repeat; +} + +.jqueryFileTree LI.ext_zip { + background: url(images/zip.png) left top no-repeat; +} \ No newline at end of file diff --git a/scripts/jquery.splitter/jquery.splitter.css b/scripts/jquery.splitter/jquery.splitter.css old mode 100755 new mode 100644 index ba2c8304..8c50809f --- a/scripts/jquery.splitter/jquery.splitter.css +++ b/scripts/jquery.splitter/jquery.splitter.css @@ -4,13 +4,11 @@ height is fixed and the width is the full width of the body, less the margin on the splitter itself. */ - #splitter { background-color: white; height: 400px; border: 1px solid #ccc; - /* border: 4px solid #E2EAF3; */ - /* No padding allowed */ + /* border: 4px solid #E2EAF3; */ /* No padding allowed */ } /* @@ -20,23 +18,19 @@ the desired initial width of the element; the plugin changes the width of this element dynamically. */ - -#filetree { - /* padding: 4px; */ +#filetree { /* padding: 4px; */ overflow: auto; - width: 30%; /* optional, initial splitbar position */ - min-width: 100px; /* optional */ - /* No margin or border allowed */ + width: 30%; /* optional, initial splitbar position */ + min-width: 100px; /* optional */ /* No margin or border allowed */ } -#filetree > ul { +#filetree>ul { padding: 4px; } /* Right-side element of the splitter. */ - #fileinfo { padding: 4px; min-width: 100px; @@ -44,18 +38,15 @@ /* No margin or border allowed */ } - /* Splitter bar style; the .active class is added when the mouse is over the splitter or the splitter is focused via the keyboard taborder or an accessKey. */ - #splitter .vsplitbar { width: 6px; background: #ccc url(vgrabber.gif) no-repeat center; } - /* #splitter .vsplitbar.active, #splitter .vsplitbar:hover { diff --git a/styles/ie.css b/styles/ie.css old mode 100755 new mode 100644 index 15585ad4..19421da0 --- a/styles/ie.css +++ b/styles/ie.css @@ -1 +1,3 @@ -* { zoom: 1; } +* { + zoom: 1; +} \ No newline at end of file diff --git a/styles/reset.css b/styles/reset.css old mode 100755 new mode 100644 index 99a02116..ff26604c --- a/styles/reset.css +++ b/styles/reset.css @@ -1 +1,44 @@ -html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0} \ No newline at end of file +html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td + { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; + vertical-align: baseline; + background: transparent +} + +body { + line-height: 1 +} + +ol,ul { + list-style: none +} + +blockquote,q { + quotes: none +} + +blockquote:before,blockquote:after,q:before,q:after { + content: ''; + content: none +} + +:focus { + outline: 0 +} + +ins { + text-decoration: none +} + +del { + text-decoration: line-through +} + +table { + border-collapse: collapse; + border-spacing: 0 +} \ No newline at end of file