summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/base64
diff options
context:
space:
mode:
Diffstat (limited to 'tcllib/modules/base64')
-rw-r--r--tcllib/modules/base64/ChangeLog428
-rw-r--r--tcllib/modules/base64/ascii85.man75
-rw-r--r--tcllib/modules/base64/ascii85.pcx65
-rw-r--r--tcllib/modules/base64/ascii85.tcl271
-rw-r--r--tcllib/modules/base64/ascii85.test189
-rw-r--r--tcllib/modules/base64/base64.bench61
-rw-r--r--tcllib/modules/base64/base64.man70
-rw-r--r--tcllib/modules/base64/base64.pcx65
-rw-r--r--tcllib/modules/base64/base64.tcl387
-rw-r--r--tcllib/modules/base64/base64.test162
-rw-r--r--tcllib/modules/base64/base64c.tcl19
-rw-r--r--tcllib/modules/base64/pkgIndex.tcl5
-rw-r--r--tcllib/modules/base64/uuencode.bench46
-rw-r--r--tcllib/modules/base64/uuencode.man97
-rw-r--r--tcllib/modules/base64/uuencode.pcx74
-rw-r--r--tcllib/modules/base64/uuencode.tcl335
-rw-r--r--tcllib/modules/base64/uuencode.test193
-rw-r--r--tcllib/modules/base64/yencode.bench46
-rw-r--r--tcllib/modules/base64/yencode.man96
-rw-r--r--tcllib/modules/base64/yencode.pcx78
-rw-r--r--tcllib/modules/base64/yencode.tcl307
-rw-r--r--tcllib/modules/base64/yencode.test99
-rw-r--r--tcllib/modules/base64/yencode.test.databin0 -> 584 bytes
-rw-r--r--tcllib/modules/base64/yencode.test.out17
24 files changed, 3185 insertions, 0 deletions
diff --git a/tcllib/modules/base64/ChangeLog b/tcllib/modules/base64/ChangeLog
new file mode 100644
index 0000000..c182107
--- /dev/null
+++ b/tcllib/modules/base64/ChangeLog
@@ -0,0 +1,428 @@
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2013-01-08 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.man: [Bug 3581373]: Document behaviour for -maxlen 0.
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-11-08 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.test: [Bug 2976290]: Disable new test when Trf is
+ available. It actually performs a decoding.
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2010-07-06 Andreas Kupries <andreask@activestate.com>
+
+ * base64.tcl (::base64::decode): [Bug 2976290]: Throw a proper
+ * base64.man: error when trying to decode padding with not enough
+ * base64.test: data in front of it. Extended testsuite. Bumped to
+ * pkgIndex.tcl: version 2.4.2.
+
+2010-05-04 Andreas Kupries <andreask@activestate.com>
+
+ * base64.man:: Fix small typo, default for -maxlen changed to 76.
+
+2010-05-03 Andreas Kupries <andreask@activestate.com>
+
+ * ascii85.man: [FR 2993200]: Added new package ascii85,
+ * ascii85.tcl: provided by Emiliano
+ * ascii85.test: <egavilan@users.sourceforge.net>
+ * pkgIndex.tcl:
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2009-05-07 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * uuencode.tcl: Changed poor idiom for setting interp result.
+ * yencode.tcl:
+
+2009-01-28 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.tcl: Define a number of transient variables in the
+ namespace, to avoid creative-writing. Fixes [Bug 2538424].
+
+ * pkgIndex.tcl: Bumped version to 2.4.1.
+ * base64.man:
+
+2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11.1 ========================
+ *
+
+2008-12-11 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * yencode.tcl: Fixed bug in the yencoder. Escaped characters
+ * yencode.man: have to be rotated by 64 according to the yEnc
+ * yencode.test: specification v1.3, not 42. Bumped version to
+ * pkgIndex.tcl: 1.1.2. Updated tests.
+
+ * uuencode.test: Better handling of loading 'tcllibc'.
+
+2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11 ========================
+ *
+
+2008-06-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.pcx: New files. Syntax definitions for the public
+ * uuencode.pcx: commands of the packages base74, uuencode,
+ * yencode.pcx: and yencode.
+
+2008-05-28 Andreas Kupries <andreask@activestate.com>
+
+ * base64.tcl: Changed the default setting for -maxlen to 76 to
+ * base64.man: coincide with MIME definitions and Trf, making
+ * base64.test: the very fast path default, with no output reflow
+ * pkgIndex.tcl: required at all. Bumped version to 2.4.
+
+ ** POTENTIAL INCOMPATIBILITY ** for all users depending on the
+ default setting to be 60.
+
+2008-05-22 Andreas Kupries <andreask@activestate.com>
+
+ * base64.test: Extended with tests using bogus values of -maxchar,
+ * base64.tcl: and non-standard values. Fixed bugs in the maxlen
+ * base64.man: handling of the pure Tcl implementation which
+ * pkgIndex.tcl: allowed the output to have more than maxlen
+ characters per line. Performance fix: Replaced Miguel's O(n^2)
+ reflow algorithm (maxlen handling after Trf) with Gustaf
+ Neumann's O(n) algorithm. Minor changes to the guarding
+ conditions by myself, and fixes for the fast cases. Bumped the
+ version to 2.3.3.
+
+2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.10 ========================
+ *
+
+2007-03-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.man: Fixed all warnings due to use of now deprecated
+ * uuencode.man: commands. Added a section about how to give
+ * yencode.man: feedback.
+
+2006-11-04 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * base64c.tcl: Silence critcl warning.
+
+2006-10-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * uuencode.test: Documentation and code (error messages) disagreed
+ * uuencode.man: about the accepted options, and tests were
+ * uuencode.tcl: missing entirely. The code additionally missed
+ some checks regarding the proper number of arguments, nor had it
+ tests checking that either. Added tests and synchronized code
+ and documentation.
+
+2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.9 ========================
+ *
+
+2006-01-22 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * yencode.test: More boilerplate simplified via use of test support.
+ * uuencode.test:
+ * base64.test:
+
+2006-01-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * yencode.test: Hooked into the new common test support code.
+ * uuencode.test:
+ * base64.test:
+
+2005-10-18 Andreas Kupries <andreask@activestate.com>
+
+ * base64.bench: Basic benchmarks for base64, uuencode,
+ * uuencode.bench: and yencode. Encode/decode of strings
+ * yencode.bench: only.
+
+2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.8 ========================
+ *
+
+2005-08-26 Andreas Kupries <andreask@activestate.com>
+
+ * uuencode.test: Deconfused the testsuite's belief of which
+ accelerators is in use. Removed superfluous output, and added a
+ flag variable for actual use of Trf, not only presence. Changed
+ definition of test 1.4 to use this flag. This is for [Tcllib SF
+ Bug 1273537].
+
+2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.man: Cleaned the doc up a bit. Especially highlighted the
+ recently added note recording binary by separating it from the
+ general description a bit (same location, new paragraph).
+
+2005-02-17 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * base64.man: Added some examples and attempted to point out that
+ proper string encoding may be needed for unicode strings.
+
+2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.7 ========================
+ *
+
+2004-08-15 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.tcl: Typo police.
+ * uuencode.tcl:
+ * uuencode.man:
+ * yencode.man:
+
+2004-07-21 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * uuencode.man: Polished a bit (options, keywords).
+ * yencode.man:
+
+2004-07-19 Andreas Kupries <andreask@activestate.com>
+
+ * base64.man: Added copyright notes for the early authors, as far
+ as I am aware of them.
+
+2004-05-23 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * uuencode.tcl: Updated version number to sync with 1.6.1
+ * uuencode.man: release
+ * pkgIndex.tcl:
+
+2004-05-23 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.6.1 ========================
+ *
+
+2004-05-23 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * uuencode.tcl: Rel. engineering. Updated version number
+ * uuencode.man: of uuencode to reflect its changes, to 1.1.1.
+ * pkgIndex.tcl:
+
+2004-03-09 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * uuencode.tcl (::uuencode::pad): don't use log package
+
+2004-02-15 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.6 ========================
+ *
+
+2003-10-24 Andreas Kupries <andreask@activestate.com>
+
+ * base64.test:
+ * base64.tcl: Applied patch fixing [Bug 821126]. Variable 'output'
+ is now initialized to empty to have it defined at all
+ times. Extended testsuite to cover the fixed cases.
+
+2003-10-21 Andreas Kupries <andreask@activestate.com>
+
+ * base64.tcl: Added code to the Trf supported 'decode'r to ignore
+ whitespace in hte encoded input. [Bug 736900].
+
+2003-07-24 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * base64c.tcl: Added the placeholder package.
+
+2003-05-14 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * Merged DEVELOPMENT branch from DEVELOPMENT-root to
+ DEVELOPMENT-merge-1 This brings in the critcl enhancements for
+ uuencode and yencode along with a few extra tests for yencode.
+
+2003-05-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.4 ========================
+ *
+
+2003-04-22 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * base64c.tcl: Added file to define the base64c C coded package.
+ * uuencode.tcl: Added critcl code into the package.
+ * yencode.tcl: Added critcl code into the package.
+
+2003-04-22 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * all: Created DEVELOPMENT branch - tagged root-DEVELOPMENT.
+ This branch contains criticl-based C code to speed up some of the
+ computationally expensive functions - generates a base64c package.
+
+2003-04-21 Andreas Kupries <andreask@pliers.activestate.com>
+
+ * uuencode.test: Added code to suppress output from the log
+ package during the test.
+
+2003-04-11 Andreas Kupries <andreask@activestate.com>
+
+ * uuencode.man:
+ * base64.tcl:
+ * base64.man:
+ * pkgIndex.tcl: Fixed bug #614591. Set version of the base64
+ package to to 2.2.2. uuencode is now at version 1.0.2
+ throughout.
+
+2003-03-24 Andreas Kupries <andreask@activestate.com>
+
+ * uuencode.test:
+ * uuencode.tcl: Fixed bug #700327, reported by Roger Niva
+ <rniva@users.sourceforge.net>. Added '--' before actual data
+ argument to prevent mishandling of data beginning with a dash
+ ('-'). Extended the testsuite to cover these cases.
+
+2003-02-23 David N. Welton <davidw@dedasys.com>
+
+ * base64.tcl: Bumped base64.tcl Tcl requirement to 8.2, swapped
+ out regsub for string map.
+
+2003-01-25 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * yencode.tcl:
+ * uuencode.tcl: Added Tcl 8.2 version requirement, bumped versions
+ and added copyright to man pages. Fixed uuencode to work with Tcl 8.2
+
+2002-06-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * pkgIndex.tcl:
+ * base64.tcl:
+ * base64.n:
+ * base64.man: Bumped base64 to version 2.2.1.
+
+ * pkgIndex.tcl:
+ * uuencode.tcl:
+ * uuencode.n:
+ * uuencode.man: Bumped uuencode to version 1.0.1.
+
+2002-05-27 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * yencode.test: Fixed SF Tcllib Bug #548354 so that the datafile
+ used by the test is found even if the build directory is outside
+ of the tcllib directory hierarchy. Original patch provided by Larry
+ Virden <lvirden@users.sourceforge.net>, changed by me to work in
+ my configuration too.
+
+2002-04-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * uuencode.tcl:
+ * yencode.tcl:
+ * base64.tcl: Fixed decoding of empty string in tcl
+ implementation. Fixes bug #548112.
+
+2002-04-17 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * yencode.tcl, yencode.test, yencode.man, yencode.test.data,
+ * yencode.test.out: initial import of yEnc encode/decode package
+ plus man page and test.
+
+2002-04-17 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * uuencode.tcl: fixed bug #544452 to handle DOS input files and
+ tolerate incorrect uuencoded line lengths.
+ * uuencode.test: added tests for the above bug conditions.
+
+2002-01-17 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * uuencode.tcl: added support for Trf and fixed length bug
+
+2002-01-16 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * uuencode.tcl: initial import of uuencode package
+ * pkgIndex.tcl: added uuencode package
+
+2001-09-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.tcl: Restricted export list to public API.
+ [456255]. Patch by Hemang Lavana
+ <hemanglavana@users.sourceforge.net>
+
+2001-07-31 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.n: Added manpage [446584].
+
+2001-07-10 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * base64.tcl: Frink 2.2 run, fixed dubious code.
+
+2001-06-21 Andreas Kupries <andreas_kupries@users.sourceforge.net
+
+ * base64.tcl: Fixed dubious code reported by frink.
+
+2001-06-02 Miguel Sofer <mig@utdt.edu>
+
+ * base64.tcl: Greatly increased speed, obtained by: using lists
+ instead of arrays, splitting the input with [binary scan],
+ taking the bytes to be encoded three at a time, and
+ reformulating the decoding algorithm to be purely
+ arithmetic. Improved backwards compatibility, now runs with
+ Tcl8.0.
+
+ Nudged version to 2.2
+
+2000-10-11 Brent Welch <welch@ajubasolutions.com>
+
+ * base64.tcl: Fixed bug in base64::decode where trailing
+ bytes were not always decoded correctly (!). This only
+ shows up with low-valued characters (less than 0x10) near
+ the end of a string that was padded with =
+
+ Nudged version to 2.1 so we can distinquish this version
+ that has bug fixes and new features.
+
+2000-10-10 Eric Melski <ericm@ajubasolutions.com>
+
+ * base64.tcl: Extending base64::encode to accept optional
+ arguments ?-maxlen maxlen? and ?-wrapchar wrapchar?, to control
+ the line wrapping and the character(s) used to cause the
+ wrapping. Based on work by Joel Saunier.
+
+2000-03-09 Eric Melski <ericm@scriptics.com>
+
+ * base64.test: Adapted tests to work in tcllib test framework.
+
+2000-03-04 Eric Melski <ericm@scriptics.com>
+
+ * base64.test: Added tests for decoding data that was padded with ='s
+
+ * base64.tcl: Fixed a bug with line wrapping in the encoder -- it
+ was not properly counting the number of characters emitted, so it
+ was not wrapping when it should. Changed the chars/line to 60, so
+ the output would be identical to that produced by GNU uuecode 4.2,
+ for easy testing purposes. Fixed a bug in the decoder with
+ newlines -- it was not ignoring them as it should according to RFC
+ 2045.
+ Fixed a bug in decoder dealing with data that was padded with ='s.
+
+
+ * base64.test: Some rudimentary tests for the encoder/decoder.
+
+2000-03-02 Eric Melski <ericm@scriptics.com>
+
+ * pkgIndex.tcl: added pkgIndex file.
diff --git a/tcllib/modules/base64/ascii85.man b/tcllib/modules/base64/ascii85.man
new file mode 100644
index 0000000..aab71a1
--- /dev/null
+++ b/tcllib/modules/base64/ascii85.man
@@ -0,0 +1,75 @@
+[manpage_begin ascii85 n 1.0]
+[keywords ascii85]
+[keywords encoding]
+[copyright "2010, Emiliano Gavil\u00e1n"]
+[moddesc {Text encoding & decoding binary data}]
+[titledesc {ascii85-encode/decode binary data}]
+[category {Text processing}]
+[require Tcl 8.4]
+[require ascii85 [opt 1.0]]
+[description]
+[para]
+
+This package provides procedures to encode binary data into ascii85 and back.
+
+[list_begin definitions]
+
+[call [cmd ::ascii85::encode] [opt "[option -maxlen] [arg maxlen]"] [opt "[option -wrapchar] [arg wrapchar]"] [arg string]]
+
+Ascii85 encodes the given binary [arg string] and returns the encoded
+result. Inserts the character [arg wrapchar] every [arg maxlen]
+characters of output. [arg wrapchar] defaults to newline. [arg maxlen]
+defaults to [const 76].
+
+[para]
+
+[emph {Note well}]: If your string is not simple ascii you should fix
+the string encoding before doing ascii85 encoding. See the examples.
+
+[para]
+
+The command will throw an error for negative values of [arg maxlen],
+or if [arg maxlen] is not an integer number.
+
+[call [cmd ::ascii85::decode] [arg "string"]]
+
+Ascii85 decodes the given [arg "string"] and returns the binary data.
+The decoder ignores whitespace in the string, as well as tabs and
+newlines.
+
+[list_end]
+
+[section {EXAMPLES}]
+
+[example {
+% ascii85::encode "Hello, world"
+87cURD_*#TDfTZ)
+}]
+
+[example {
+% ascii85::encode [string repeat xyz 24]
+G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G
+^4U[H$X^\H?a^]
+% ascii85::encode -wrapchar "" [string repeat xyz 24]
+G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]G^4U[H$X^\H?a^]
+}]
+
+[example {
+# NOTE: ascii85 encodes BINARY strings.
+% set chemical [encoding convertto utf-8 "C\u2088H\u2081\u2080N\u2084O\u2082"]
+% set encoded [ascii85::encode $chemical]
+6fN]R8E,5Pidu\UiduhZidua
+% set caffeine [encoding convertfrom utf-8 [ascii85::decode $encoded]]
+}]
+
+[section References]
+
+[list_begin enum]
+[enum] [uri http://en.wikipedia.org/wiki/Ascii85]
+[enum] Postscript Language Reference Manual, 3rd Edition, page 131.
+ [uri http://www.adobe.com/devnet/postscript/pdfs/PLRM.pdf]
+[list_end]
+
+[vset CATEGORY base64]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/base64/ascii85.pcx b/tcllib/modules/base64/ascii85.pcx
new file mode 100644
index 0000000..a300ccd
--- /dev/null
+++ b/tcllib/modules/base64/ascii85.pcx
@@ -0,0 +1,65 @@
+# -*- tcl -*- ascii85.pcx
+# Syntax of the commands provided by package ascii85.
+#
+# For use by TclDevKit's static syntax checker.
+# See http://www.activestate.com/solutions/tcl/
+# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
+# for the documentation describing the format of the code contained in this file
+#
+
+package require pcx
+pcx::register ascii85
+pcx::tcldep 1.0 needs tcl 8.4
+
+namespace eval ::ascii85 {}
+
+# Using the indirections below looks to be quite pointless, given that
+# they simply substitute the commands for others. I am doing this for
+# two reasons.
+
+# First, the rules coming after become self-commenting, i.e. a
+# maintainer can immediately see what an argument is supposed to be,
+# instead of having to search elsewhere (like the documentation and
+# implementation). In this manner our definitions here are a type of
+# semantic markup.
+
+# The second reason is that while we have no special checks now we
+# cannot be sure if such will (have to) be added in the future. With
+# all checking routed through our definitions we now already have the
+# basic infrastructure (i.e. hooks) in place in which we can easily
+# add any new checks by simply redefining the relevant command, and
+# all the rules update on their own. Mostly. This should cover 90% of
+# the cases. Sometimes new checks will require to create deeper
+# distinctions between different calls of the same thing. For such we
+# may have to update the rules as well, to provide the necessary
+# information to the checker.
+
+interp alias {} ascii85::checkLineLength {} checkInt ; #
+interp alias {} ascii85::checkWrapChar {} checkWord ; #
+interp alias {} ascii85::checkData {} checkWord ; #
+
+#pcx::message FOO {... text ...} type
+#pcx::scan <VERSION> <NAME> <RULE>
+
+pcx::check 1.0 std ::ascii85::decode \
+ {checkSimpleArgs 1 1 {
+ ascii85::checkData
+ }}
+
+# NOTE: Is '-maxlen' < 0 allowed?
+# Doc doesn't forbid it, code doesn't catch it.
+# May crash it however, i.e be a bug.
+# Check testsuite.
+pcx::check 1.0 std ::ascii85::encode \
+ {checkSimpleArgs 1 -1 {
+ {checkSwitches 1 {
+ {-maxlen ascii85::checkLineLength}
+ {-wrapchar ascii85::checkWrapChar}
+ } {checkSimpleArgs 1 1 {
+ ascii85::checkData
+ }}}
+ }}
+
+# Initialization via pcx::init.
+# Use a ::ascii85::init procedure for non-standard initialization.
+pcx::complete
diff --git a/tcllib/modules/base64/ascii85.tcl b/tcllib/modules/base64/ascii85.tcl
new file mode 100644
index 0000000..9a1cd04
--- /dev/null
+++ b/tcllib/modules/base64/ascii85.tcl
@@ -0,0 +1,271 @@
+# ascii85.tcl --
+#
+# Encode/Decode ascii85 for a string
+#
+# Copyright (c) Emiliano Gavilan
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+package require Tcl 8.4
+
+namespace eval ascii85 {
+ namespace export encode encodefile decode
+ # default values for encode options
+ variable options
+ array set options [list -wrapchar \n -maxlen 76]
+}
+
+# ::ascii85::encode --
+#
+# Ascii85 encode a given string.
+#
+# Arguments:
+# args ?-maxlen maxlen? ?-wrapchar wrapchar? string
+#
+# If maxlen is 0, the output is not wrapped.
+#
+# Results:
+# A Ascii85 encoded version of $string, wrapped at $maxlen characters
+# by $wrapchar.
+
+proc ascii85::encode {args} {
+ variable options
+
+ set alen [llength $args]
+ if {$alen != 1 && $alen != 3 && $alen != 5} {
+ return -code error "wrong # args:\
+ should be \"[lindex [info level 0] 0]\
+ ?-maxlen maxlen?\
+ ?-wrapchar wrapchar? string\""
+ }
+
+ set data [lindex $args end]
+ array set opts [array get options]
+ array set opts [lrange $args 0 end-1]
+ foreach key [array names opts] {
+ if {[lsearch -exact [array names options] $key] == -1} {
+ return -code error "unknown option \"$key\":\
+ must be -maxlen or -wrapchar"
+ }
+ }
+
+ if {![string is integer -strict $opts(-maxlen)]
+ || $opts(-maxlen) < 0} {
+ return -code error "expected positive integer but got\
+ \"$opts(-maxlen)\""
+ }
+
+ # perform this check early
+ if {[string length $data] == 0} {
+ return ""
+ }
+
+ # shorten the names
+ set ml $opts(-maxlen)
+ set wc $opts(-wrapchar)
+
+ # if maxlen is zero, don't wrap the output
+ if {$ml == 0} {
+ set wc ""
+ }
+
+ set encoded {}
+
+ binary scan $data c* X
+ set len [llength $X]
+ set rest [expr {$len % 4}]
+ set lastidx [expr {$len - $rest - 1}]
+
+ foreach {b1 b2 b3 b4} [lrange $X 0 $lastidx] {
+ # calculate the 32 bit value
+ # this is an inlined version of the [encode4bytes] proc
+ # included here for performance reasons
+ set val [expr {
+ ( (($b1 & 0xff) << 24)
+ |(($b2 & 0xff) << 16)
+ |(($b3 & 0xff) << 8)
+ | ($b4 & 0xff)
+ ) & 0xffffffff }]
+
+ if {$val == 0} {
+ # four \0 bytes encodes as "z" instead of "!!!!!"
+ append current "z"
+ } else {
+ # no magic numbers here.
+ # 52200625 -> 85 ** 4
+ # 614125 -> 85 ** 3
+ # 7225 -> 85 ** 2
+ append current [binary format ccccc \
+ [expr { ( $val / 52200625) + 33 }] \
+ [expr { (($val % 52200625) / 614125) + 33 }] \
+ [expr { (($val % 614125) / 7225) + 33 }] \
+ [expr { (($val % 7225) / 85) + 33 }] \
+ [expr { ( $val % 85) + 33 }]]
+ }
+
+ if {[string length $current] >= $ml} {
+ append encoded [string range $current 0 [expr {$ml - 1}]] $wc
+ set current [string range $current $ml end]
+ }
+ }
+
+ if { $rest } {
+ # there are remaining bytes.
+ # pad with \0 and encode not using the "z" convention.
+ # finally, add ($rest + 1) chars.
+ set val 0
+ foreach {b1 b2 b3 b4} [pad [lrange $X [incr lastidx] end] 4 0] break
+ append current [string range [encode4bytes $b1 $b2 $b3 $b4] 0 $rest]
+ }
+ append encoded [regsub -all -- ".{$ml}" $current "&$wc"]
+
+ return $encoded
+}
+
+proc ascii85::encode4bytes {b1 b2 b3 b4} {
+ set val [expr {
+ ( (($b1 & 0xff) << 24)
+ |(($b2 & 0xff) << 16)
+ |(($b3 & 0xff) << 8)
+ | ($b4 & 0xff)
+ ) & 0xffffffff }]
+ return [binary format ccccc \
+ [expr { ( $val / 52200625) + 33 }] \
+ [expr { (($val % 52200625) / 614125) + 33 }] \
+ [expr { (($val % 614125) / 7225) + 33 }] \
+ [expr { (($val % 7225) / 85) + 33 }] \
+ [expr { ( $val % 85) + 33 }]]
+}
+
+# ::ascii85::encodefile --
+#
+# Ascii85 encode the contents of a file using default values
+# for maxlen and wrapchar parameters.
+#
+# Arguments:
+# fname The name of the file to encode.
+#
+# Results:
+# An Ascii85 encoded version of the contents of the file.
+# This is a convenience command
+
+proc ascii85::encodefile {fname} {
+ set fd [open $fname]
+ fconfigure $fd -encoding binary -translation binary
+ return [encode [read $fd]][close $fd]
+}
+
+# ::ascii85::decode --
+#
+# Ascii85 decode a given string.
+#
+# Arguments:
+# string The string to decode.
+# Leading spaces and tabs are removed, along with trailing newlines
+#
+# Results:
+# The decoded value.
+
+proc ascii85::decode {data} {
+ # get rid of leading spaces/tabs and trailing newlines
+ set data [string map [list \n {} \t {} { } {}] $data]
+ set len [string length $data]
+
+ # perform this ckeck early
+ if {! $len} {
+ return ""
+ }
+
+ set decoded {}
+ set count 0
+ set group [list]
+ binary scan $data c* X
+
+ foreach char $X {
+ # we must check that every char is in the allowed range
+ if {$char < 33 || $char > 117 } {
+ # "z" is an exception
+ if {$char == 122} {
+ if {$count == 0} {
+ # if a "z" char appears at the beggining of a group,
+ # it decodes as four null bytes
+ append decoded \x00\x00\x00\x00
+ continue
+ } else {
+ # if not, is an error
+ return -code error \
+ "error decoding data: \"z\" char misplaced"
+ }
+ }
+ # char is not in range and not a "z" at the beggining of a group
+ return -code error \
+ "error decoding data: chars outside the allowed range"
+ }
+
+ lappend group $char
+ incr count
+ if {$count == 5} {
+ # this is an inlined version of the [decode5chars] proc
+ # included here for performance reasons
+ set val [expr {
+ ([lindex $group 0] - 33) * wide(52200625) +
+ ([lindex $group 1] - 33) * 614125 +
+ ([lindex $group 2] - 33) * 7225 +
+ ([lindex $group 3] - 33) * 85 +
+ ([lindex $group 4] - 33) }]
+ if {$val > 0xffffffff} {
+ return -code error "error decoding data: decoded group overflow"
+ } else {
+ append decoded [binary format I $val]
+ incr count -5
+ set group [list]
+ }
+ }
+ }
+
+ set len [llength $group]
+ switch -- $len {
+ 0 {
+ # all input has been consumed
+ # do nothing
+ }
+ 1 {
+ # a single char is a condition error, there should be at least 2
+ return -code error \
+ "error decoding data: trailing char"
+ }
+ default {
+ # pad with "u"s, decode and add ($len - 1) bytes
+ append decoded [string range \
+ [decode5chars [pad $group 5 122]] \
+ 0 \
+ [expr {$len - 2}]]
+ }
+ }
+
+ return $decoded
+}
+
+proc ascii85::decode5chars {group} {
+ set val [expr {
+ ([lindex $group 0] - 33) * wide(52200625) +
+ ([lindex $group 1] - 33) * 614125 +
+ ([lindex $group 2] - 33) * 7225 +
+ ([lindex $group 3] - 33) * 85 +
+ ([lindex $group 4] - 33) }]
+ if {$val > 0xffffffff} {
+ return -code error "error decoding data: decoded group overflow"
+ }
+
+ return [binary format I $val]
+}
+
+proc ascii85::pad {chars len padchar} {
+ while {[llength $chars] < $len} {
+ lappend chars $padchar
+ }
+
+ return $chars
+}
+
+package provide ascii85 1.0
diff --git a/tcllib/modules/base64/ascii85.test b/tcllib/modules/base64/ascii85.test
new file mode 100644
index 0000000..7b249d9
--- /dev/null
+++ b/tcllib/modules/base64/ascii85.test
@@ -0,0 +1,189 @@
+# Tests for the base64 module. -*- tcl -*-
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# All rights reserved.
+#
+# RCS: @(#) $Id: ascii85.test,v 1.1 2010/05/03 21:48:39 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+package require tcltest
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 1.0
+
+testing {
+ useLocal ascii85.tcl ascii85
+}
+
+# -------------------------------------------------------------------------
+# Encoding tests
+# -------------------------------------------------------------------------
+
+test ascii85-1.1 {ascii85::encode} {
+ ascii85::encode "this is a test\n"
+} {FD,B0+DGm>@3BZ'F*%`}
+
+test ascii85-1.2 {ascii85::encode wraps lines at 76 characters} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ ascii85::encode $str
+} {<+ohcF(fK4F<GU8A0>K&GT_$8DBNqABk(ppGp%3BEc6)5BHVD1AKYW+AS#a%AnbgmA0>;uA0>W0D
+/a&s+E)F7EZfI;AKZ)'Cht5'Ec6/>+C\njEXD}
+
+test ascii85-1.3 {ascii85::encode with wrap length set to 60} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ ascii85::encode -maxlen 60 $str
+} {<+ohcF(fK4F<GU8A0>K&GT_$8DBNqABk(ppGp%3BEc6)5BHVD1AKYW+AS#a%
+AnbgmA0>;uA0>W0D/a&s+E)F7EZfI;AKZ)'Cht5'Ec6/>+C\njEXD}
+
+test ascii85-1.4 {ascii85::encode with wrap length set to 0} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ ascii85::encode -maxlen 0 $str
+} {<+ohcF(fK4F<GU8A0>K&GT_$8DBNqABk(ppGp%3BEc6)5BHVD1AKYW+AS#a%AnbgmA0>;uA0>W0D/a&s+E)F7EZfI;AKZ)'Cht5'Ec6/>+C\njEXD}
+
+test ascii85-1.5 {ascii85::encode with wrap length set to 76, wrapchar to newline+space} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ ascii85::encode -maxlen 76 -wrapchar "\n " $str
+} {<+ohcF(fK4F<GU8A0>K&GT_$8DBNqABk(ppGp%3BEc6)5BHVD1AKYW+AS#a%AnbgmA0>;uA0>W0D
+ /a&s+E)F7EZfI;AKZ)'Cht5'Ec6/>+C\njEXD}
+
+test ascii85-1.6 {ascii85::encode, errors} {
+ list [catch {ascii85::encode} msg] $msg
+} [list 1 "wrong # args: should be \"ascii85::encode ?-maxlen maxlen? ?-wrapchar wrapchar? string\""]
+
+test ascii85-1.7 {ascii85::encode, errors} {
+ list [catch {ascii85::encode -maxlen foo} msg] $msg
+} [list 1 "wrong # args: should be \"ascii85::encode ?-maxlen maxlen? ?-wrapchar wrapchar? string\""]
+
+# changed form the original. ascii85 checks for correct # args before
+# checking for valid options. Now this test is duplicate of 1.12
+test ascii85-1.8 {ascii85::encode, errors} {
+ list [catch {ascii85::encode -maxlen foo bar} msg] $msg
+} [list 1 {expected positive integer but got "foo"}]
+
+test ascii85-1.9 {ascii85::encode, errors} {
+ list [catch {ascii85::encode -maxlen foo -wrapchar bar} msg] $msg
+} [list 1 "wrong # args: should be \"ascii85::encode ?-maxlen maxlen? ?-wrapchar wrapchar? string\""]
+
+test ascii85-1.10 {ascii85::encode, errors} {
+ list [catch {ascii85::encode -foo bar baz} msg] $msg
+} [list 1 "unknown option \"-foo\": must be -maxlen or -wrapchar"]
+
+test ascii85-1.11 {ascii85::encode with bogus wrap length (< 0)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ list [catch { ascii85::encode -maxlen -3 $str } msg] $msg
+} {1 {expected positive integer but got "-3"}}
+
+# dulicate of 1.8
+test ascii85-1.12 {ascii85::encode with bogus wrap length (non-numeric)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ list [catch { ascii85::encode -maxlen foo $str } msg] $msg
+} {1 {expected positive integer but got "foo"}}
+
+test ascii85-1.13 {ascii85::encode with bogus wrap length (non-integer)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ list [catch { ascii85::encode -maxlen 1.5 $str } msg] $msg
+} {1 {expected positive integer but got "1.5"}}
+
+test ascii85-1.14 {ascii85::encode with wrap length set to 20} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ ascii85::encode -maxlen 20 $str
+} {<+ohcF(fK4F<GU8A0>K&
+GT_$8DBNqABk(ppGp%3B
+Ec6)5BHVD1AKYW+AS#a%
+AnbgmA0>;uA0>W0D/a&s
++E)F7EZfI;AKZ)'Cht5'
+Ec6/>+C\njEXD}
+
+test ascii85-1.15 {ascii85::encode with wrap length set to 23 (prime)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ ascii85::encode -maxlen 23 $str
+} {<+ohcF(fK4F<GU8A0>K&GT_
+$8DBNqABk(ppGp%3BEc6)5B
+HVD1AKYW+AS#a%AnbgmA0>;
+uA0>W0D/a&s+E)F7EZfI;AK
+Z)'Cht5'Ec6/>+C\njEXD}
+
+test ascii85-1.16 {ascii85::encode string of length zero} {
+ ascii85::encode ""
+} ""
+
+# -------------------------------------------------------------------------
+# Decoding tests
+# -------------------------------------------------------------------------
+
+test ascii85-2.1 {ascii85::decode} {
+ ascii85::decode {FD,B0+DGm>@3BZ'F*%`}
+} "this is a test\n"
+
+test ascii85-2.2 {ascii85::decode ignores newlines} {
+ set str {<+ohcF(fK4F<GU8A0>K&GT_$8DBNqABk(ppGp%3BEc6)5BHVD1AKYW+AS#a%AnbgmA0>;uA0>W0D}
+ append str \n
+ append str {/a&s+E)F7EZfI;AKZ)'Cht5'Ec6/>+C\njEXD}
+ ascii85::decode $str
+} "The short red fox ran quickly through the green field and jumped over the tall brown bear\n"
+
+test ascii85-2.3 {ascii85::decode error chars not in range} {
+ list [catch {ascii85::decode "ab~cd"} msg] $msg
+} {1 {error decoding data: chars outside the allowed range}}
+
+test ascii85-2.4 {ascii85::decode error "z" char misplaced} {
+ list [catch {ascii85::decode "abczd"} msg] $msg
+} {1 {error decoding data: "z" char misplaced}}
+
+test ascii85-2.5 {ascii85::decode error trailing char} {
+ list [catch {ascii85::decode "abcde5"} msg] $msg
+} {1 {error decoding data: trailing char}}
+
+test ascii85-2.6 {ascii85::decode decoding of null chars} {
+ foreach enc [list !! !!! !!!! z z!!] {
+ lappend res [ascii85::decode $enc]
+ }
+ set res
+} [list \x00 \x00\x00 \x00\x00\x00 \x00\x00\x00\x00 \x00\x00\x00\x00\x00]
+
+test ascii85-2.7 {ascii85::decode integer range limit} {
+ ascii85::decode s8W-!
+} "\xff\xff\xff\xff"
+
+test ascii85-2.8 {ascii85::decode integer range overflow} {
+ list [catch {ascii85::decode {s8W-"}} msg] $msg
+} {1 {error decoding data: decoded group overflow}}
+
+test ascii85-2.9 {ascii85::decode of empty string} {
+ ascii85::decode ""
+} ""
+
+# -------------------------------------------------------------------------
+# Identity tests
+# -------------------------------------------------------------------------
+
+test ascii85-3.1 {ascii85 identity test} {
+ ascii85::decode [ascii85::encode "this is a test"]
+} "this is a test"
+
+test ascii85-3.2 {base64 identity test} {
+ set x \f\xee
+ set y [ascii85::decode [ascii85::encode $x]]
+ string compare $x $y
+} 0
+
+testsuiteCleanup
+return
diff --git a/tcllib/modules/base64/base64.bench b/tcllib/modules/base64/base64.bench
new file mode 100644
index 0000000..edfc2ef
--- /dev/null
+++ b/tcllib/modules/base64/base64.bench
@@ -0,0 +1,61 @@
+# -*- tcl -*-
+# Tcl Benchmark File
+#
+# This file contains a number of benchmarks for the 'base64' module.
+# This allow developers to monitor/gauge/track package performance.
+#
+# (c) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+# We need at least version 8.2 for the package and thus the
+# benchmarks.
+
+if {![package vsatisfies [package provide Tcl] 8.2]} {
+ return
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Setting up the environment ...
+
+set moddir [file dirname [file dirname [info script]]]
+lappend auto_path $moddir
+
+package forget base64
+catch {namespace delete ::base64}
+source [file join [file dirname [info script]] base64.tcl]
+
+# ### ### ### ######### ######### ######### ###########################
+## Benchmarks.
+
+
+foreach n {10 100 1000 10000} {
+ bench -desc "BASE64 encode ${n}X" -pre {
+ set str [string repeat X $n]
+ } -body {
+ base64::encode $str
+ } -post {
+ unset str
+ }
+
+ bench -desc "BASE64 decode ${n}X" -pre {
+ set str [base64::encode [string repeat X $n]]
+ } -body {
+ base64::decode $str
+ } -post {
+ unset str
+ }
+}
+
+foreach wrap {1 10 60 100} {
+ foreach n {10 100 1000 10000} {
+ bench -desc "BASE64 encode ${n}X -wrap $wrap" -pre {
+ set str [string repeat X $n]
+ } -body {
+ base64::encode -wrap $wrap $str
+ } -post {
+ unset str
+ }
+ }
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Complete
diff --git a/tcllib/modules/base64/base64.man b/tcllib/modules/base64/base64.man
new file mode 100644
index 0000000..c20274c
--- /dev/null
+++ b/tcllib/modules/base64/base64.man
@@ -0,0 +1,70 @@
+[manpage_begin base64 n 2.4.2]
+[keywords base64]
+[keywords encoding]
+[copyright {2000, Eric Melski}]
+[copyright {2001, Miguel Sofer}]
+[moddesc {Text encoding & decoding binary data}]
+[titledesc {base64-encode/decode binary data}]
+[category {Text processing}]
+[require Tcl 8]
+[require base64 [opt 2.4.2]]
+[description]
+[para]
+
+This package provides procedures to encode binary data into base64 and back.
+
+[list_begin definitions]
+
+[call [cmd ::base64::encode] [opt "[option -maxlen] [arg maxlen]"] [opt "[option -wrapchar] [arg wrapchar]"] [arg string]]
+
+Base64 encodes the given binary [arg string] and returns the encoded
+result. Inserts the character [arg wrapchar] every [arg maxlen]
+characters of output. [arg wrapchar] defaults to newline. [arg maxlen]
+defaults to [const 76].
+
+[para] [emph Note] that if [arg maxlen] is set to [const 0], the
+output will not be wrapped at all.
+
+[para]
+
+[emph {Note well}]: If your string is not simple ascii you should fix
+the string encoding before doing base64 encoding. See the examples.
+
+[para]
+
+The command will throw an error for negative values of [arg maxlen],
+or if [arg maxlen] is not an integer number.
+
+[call [cmd ::base64::decode] [arg "string"]]
+
+Base64 decodes the given [arg "string"] and returns the binary data.
+The decoder ignores whitespace in the string.
+
+[list_end]
+
+[section {EXAMPLES}]
+
+[example {
+% base64::encode "Hello, world"
+SGVsbG8sIHdvcmxk
+}]
+
+[example {
+% base64::encode [string repeat xyz 20]
+eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6
+eHl6eHl6eHl6
+% base64::encode -wrapchar "" [string repeat xyz 20]
+eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6eHl6
+}]
+
+[example {
+# NOTE: base64 encodes BINARY strings.
+% set chemical [encoding convertto utf-8 "C\u2088H\u2081\u2080N\u2084O\u2082"]
+% set encoded [base64::encode $chemical]
+Q+KCiEjigoHigoBO4oKET+KCgg==
+% set caffeine [encoding convertfrom utf-8 [base64::decode $encoded]]
+}]
+
+[vset CATEGORY base64]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/base64/base64.pcx b/tcllib/modules/base64/base64.pcx
new file mode 100644
index 0000000..f61f4c0
--- /dev/null
+++ b/tcllib/modules/base64/base64.pcx
@@ -0,0 +1,65 @@
+# -*- tcl -*- base64.pcx
+# Syntax of the commands provided by package base64.
+#
+# For use by TclDevKit's static syntax checker.
+# See http://www.activestate.com/solutions/tcl/
+# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
+# for the documentation describing the format of the code contained in this file
+#
+
+package require pcx
+pcx::register base64
+pcx::tcldep 2.3.2 needs tcl 8.2
+
+namespace eval ::base64 {}
+
+# Using the indirections below looks to be quite pointless, given that
+# they simply substitute the commands for others. I am doing this for
+# two reasons.
+
+# First, the rules coming after become self-commenting, i.e. a
+# maintainer can immediately see what an argument is supposed to be,
+# instead of having to search elsewhere (like the documentation and
+# implementation). In this manner our definitions here are a type of
+# semantic markup.
+
+# The second reason is that while we have no special checks now we
+# cannot be sure if such will (have to) be added in the future. With
+# all checking routed through our definitions we now already have the
+# basic infrastructure (i.e. hooks) in place in which we can easily
+# add any new checks by simply redefining the relevant command, and
+# all the rules update on their own. Mostly. This should cover 90% of
+# the cases. Sometimes new checks will require to create deeper
+# distinctions between different calls of the same thing. For such we
+# may have to update the rules as well, to provide the necessary
+# information to the checker.
+
+interp alias {} base64::checkLineLength {} checkInt ; #
+interp alias {} base64::checkWrapChar {} checkWord ; #
+interp alias {} base64::checkData {} checkWord ; #
+
+#pcx::message FOO {... text ...} type
+#pcx::scan <VERSION> <NAME> <RULE>
+
+pcx::check 2.3.2 std ::base64::decode \
+ {checkSimpleArgs 1 1 {
+ base64::checkData
+ }}
+
+# NOTE: Is '-maxlen' < 0 allowed?
+# Doc doesn't forbid it, code doesn't catch it.
+# May crash it however, i.e be a bug.
+# Check testsuite.
+pcx::check 2.3.2 std ::base64::encode \
+ {checkSimpleArgs 1 -1 {
+ {checkSwitches 1 {
+ {-maxlen base64::checkLineLength}
+ {-wrapchar base64::checkWrapChar}
+ } {checkSimpleArgs 1 1 {
+ base64::checkData
+ }}}
+ }}
+
+# Initialization via pcx::init.
+# Use a ::base64::init procedure for non-standard initialization.
+pcx::complete
diff --git a/tcllib/modules/base64/base64.tcl b/tcllib/modules/base64/base64.tcl
new file mode 100644
index 0000000..5d3d538
--- /dev/null
+++ b/tcllib/modules/base64/base64.tcl
@@ -0,0 +1,387 @@
+# base64.tcl --
+#
+# Encode/Decode base64 for a string
+# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
+# The decoder was done for exmh by Chris Garrigues
+#
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: base64.tcl,v 1.32 2010/07/06 19:15:40 andreas_kupries Exp $
+
+# Version 1.0 implemented Base64_Encode, Base64_Decode
+# Version 2.0 uses the base64 namespace
+# Version 2.1 fixes various decode bugs and adds options to encode
+# Version 2.2 is much faster, Tcl8.0 compatible
+# Version 2.2.1 bugfixes
+# Version 2.2.2 bugfixes
+# Version 2.3 bugfixes and extended to support Trf
+
+# @mdgen EXCLUDE: base64c.tcl
+
+package require Tcl 8.2
+namespace eval ::base64 {
+ namespace export encode decode
+}
+
+if {![catch {package require Trf 2.0}]} {
+ # Trf is available, so implement the functionality provided here
+ # in terms of calls to Trf for speed.
+
+ # ::base64::encode --
+ #
+ # Base64 encode a given string.
+ #
+ # Arguments:
+ # args ?-maxlen maxlen? ?-wrapchar wrapchar? string
+ #
+ # If maxlen is 0, the output is not wrapped.
+ #
+ # Results:
+ # A Base64 encoded version of $string, wrapped at $maxlen characters
+ # by $wrapchar.
+
+ proc ::base64::encode {args} {
+ # Set the default wrapchar and maximum line length to match
+ # the settings for MIME encoding (RFC 3548, RFC 2045). These
+ # are the settings used by Trf as well. Various RFCs allow for
+ # different wrapping characters and wraplengths, so these may
+ # be overridden by command line options.
+ set wrapchar "\n"
+ set maxlen 76
+
+ if { [llength $args] == 0 } {
+ error "wrong # args: should be \"[lindex [info level 0] 0]\
+ ?-maxlen maxlen? ?-wrapchar wrapchar? string\""
+ }
+
+ set optionStrings [list "-maxlen" "-wrapchar"]
+ for {set i 0} {$i < [llength $args] - 1} {incr i} {
+ set arg [lindex $args $i]
+ set index [lsearch -glob $optionStrings "${arg}*"]
+ if { $index == -1 } {
+ error "unknown option \"$arg\": must be -maxlen or -wrapchar"
+ }
+ incr i
+ if { $i >= [llength $args] - 1 } {
+ error "value for \"$arg\" missing"
+ }
+ set val [lindex $args $i]
+
+ # The name of the variable to assign the value to is extracted
+ # from the list of known options, all of which have an
+ # associated variable of the same name as the option without
+ # a leading "-". The [string range] command is used to strip
+ # of the leading "-" from the name of the option.
+ #
+ # FRINK: nocheck
+ set [string range [lindex $optionStrings $index] 1 end] $val
+ }
+
+ # [string is] requires Tcl8.2; this works with 8.0 too
+ if {[catch {expr {$maxlen % 2}}]} {
+ return -code error "expected integer but got \"$maxlen\""
+ } elseif {$maxlen < 0} {
+ return -code error "expected positive integer but got \"$maxlen\""
+ }
+
+ set string [lindex $args end]
+ set result [::base64 -mode encode -- $string]
+
+ # Trf's encoder implicitly uses the settings -maxlen 76,
+ # -wrapchar \n for its output. We may have to reflow this for
+ # the settings chosen by the user. A second difference is that
+ # Trf closes the output with the wrap char sequence,
+ # always. The code here doesn't. Therefore 'trimright' is
+ # needed in the fast cases.
+
+ if {($maxlen == 76) && [string equal $wrapchar \n]} {
+ # Both maxlen and wrapchar are identical to Trf's
+ # settings. This is the super-fast case, because nearly
+ # nothing has to be done. Only thing to do is strip a
+ # terminating wrapchar.
+ set result [string trimright $result]
+ } elseif {$maxlen == 76} {
+ # wrapchar has to be different here, length is the
+ # same. We can use 'string map' to transform the wrap
+ # information.
+ set result [string map [list \n $wrapchar] \
+ [string trimright $result]]
+ } elseif {$maxlen == 0} {
+ # Have to reflow the output to no wrapping. Another fast
+ # case using only 'string map'. 'trimright' is not needed
+ # here.
+
+ set result [string map [list \n ""] $result]
+ } else {
+ # Have to reflow the output from 76 to the chosen maxlen,
+ # and possibly change the wrap sequence as well.
+
+ # Note: After getting rid of the old wrap sequence we
+ # extract the relevant segments from the string without
+ # modifying the string. Modification, i.e. removal of the
+ # processed part, means 'shifting down characters in
+ # memory', making the algorithm O(n^2). By avoiding the
+ # modification we stay in O(n).
+
+ set result [string map [list \n ""] $result]
+ set l [expr {[string length $result]-$maxlen}]
+ for {set off 0} {$off < $l} {incr off $maxlen} {
+ append res [string range $result $off [expr {$off+$maxlen-1}]] $wrapchar
+ }
+ append res [string range $result $off end]
+ set result $res
+ }
+
+ return $result
+ }
+
+ # ::base64::decode --
+ #
+ # Base64 decode a given string.
+ #
+ # Arguments:
+ # string The string to decode. Characters not in the base64
+ # alphabet are ignored (e.g., newlines)
+ #
+ # Results:
+ # The decoded value.
+
+ proc ::base64::decode {string} {
+ regsub -all {\s} $string {} string
+ ::base64 -mode decode -- $string
+ }
+
+} else {
+ # Without Trf use a pure tcl implementation
+
+ namespace eval base64 {
+ variable base64 {}
+ variable base64_en {}
+
+ # We create the auxiliary array base64_tmp, it will be unset later.
+ variable base64_tmp
+ variable i
+
+ set i 0
+ foreach char {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
+ a b c d e f g h i j k l m n o p q r s t u v w x y z \
+ 0 1 2 3 4 5 6 7 8 9 + /} {
+ set base64_tmp($char) $i
+ lappend base64_en $char
+ incr i
+ }
+
+ #
+ # Create base64 as list: to code for instance C<->3, specify
+ # that [lindex $base64 67] be 3 (C is 67 in ascii); non-coded
+ # ascii chars get a {}. we later use the fact that lindex on a
+ # non-existing index returns {}, and that [expr {} < 0] is true
+ #
+
+ # the last ascii char is 'z'
+ variable char
+ variable len
+ variable val
+
+ scan z %c len
+ for {set i 0} {$i <= $len} {incr i} {
+ set char [format %c $i]
+ set val {}
+ if {[info exists base64_tmp($char)]} {
+ set val $base64_tmp($char)
+ } else {
+ set val {}
+ }
+ lappend base64 $val
+ }
+
+ # code the character "=" as -1; used to signal end of message
+ scan = %c i
+ set base64 [lreplace $base64 $i $i -1]
+
+ # remove unneeded variables
+ unset base64_tmp i char len val
+
+ namespace export encode decode
+ }
+
+ # ::base64::encode --
+ #
+ # Base64 encode a given string.
+ #
+ # Arguments:
+ # args ?-maxlen maxlen? ?-wrapchar wrapchar? string
+ #
+ # If maxlen is 0, the output is not wrapped.
+ #
+ # Results:
+ # A Base64 encoded version of $string, wrapped at $maxlen characters
+ # by $wrapchar.
+
+ proc ::base64::encode {args} {
+ set base64_en $::base64::base64_en
+
+ # Set the default wrapchar and maximum line length to match
+ # the settings for MIME encoding (RFC 3548, RFC 2045). These
+ # are the settings used by Trf as well. Various RFCs allow for
+ # different wrapping characters and wraplengths, so these may
+ # be overridden by command line options.
+ set wrapchar "\n"
+ set maxlen 76
+
+ if { [llength $args] == 0 } {
+ error "wrong # args: should be \"[lindex [info level 0] 0]\
+ ?-maxlen maxlen? ?-wrapchar wrapchar? string\""
+ }
+
+ set optionStrings [list "-maxlen" "-wrapchar"]
+ for {set i 0} {$i < [llength $args] - 1} {incr i} {
+ set arg [lindex $args $i]
+ set index [lsearch -glob $optionStrings "${arg}*"]
+ if { $index == -1 } {
+ error "unknown option \"$arg\": must be -maxlen or -wrapchar"
+ }
+ incr i
+ if { $i >= [llength $args] - 1 } {
+ error "value for \"$arg\" missing"
+ }
+ set val [lindex $args $i]
+
+ # The name of the variable to assign the value to is extracted
+ # from the list of known options, all of which have an
+ # associated variable of the same name as the option without
+ # a leading "-". The [string range] command is used to strip
+ # of the leading "-" from the name of the option.
+ #
+ # FRINK: nocheck
+ set [string range [lindex $optionStrings $index] 1 end] $val
+ }
+
+ # [string is] requires Tcl8.2; this works with 8.0 too
+ if {[catch {expr {$maxlen % 2}}]} {
+ return -code error "expected integer but got \"$maxlen\""
+ } elseif {$maxlen < 0} {
+ return -code error "expected positive integer but got \"$maxlen\""
+ }
+
+ set string [lindex $args end]
+
+ set result {}
+ set state 0
+ set length 0
+
+
+ # Process the input bytes 3-by-3
+
+ binary scan $string c* X
+
+ foreach {x y z} $X {
+ ADD [lindex $base64_en [expr {($x >>2) & 0x3F}]]
+ if {$y != {}} {
+ ADD [lindex $base64_en [expr {(($x << 4) & 0x30) | (($y >> 4) & 0xF)}]]
+ if {$z != {}} {
+ ADD [lindex $base64_en [expr {(($y << 2) & 0x3C) | (($z >> 6) & 0x3)}]]
+ ADD [lindex $base64_en [expr {($z & 0x3F)}]]
+ } else {
+ set state 2
+ break
+ }
+ } else {
+ set state 1
+ break
+ }
+ }
+ if {$state == 1} {
+ ADD [lindex $base64_en [expr {(($x << 4) & 0x30)}]]
+ ADD =
+ ADD =
+ } elseif {$state == 2} {
+ ADD [lindex $base64_en [expr {(($y << 2) & 0x3C)}]]
+ ADD =
+ }
+ return $result
+ }
+
+ proc ::base64::ADD {x} {
+ # The line length check is always done before appending so
+ # that we don't get an extra newline if the output is a
+ # multiple of $maxlen chars long.
+
+ upvar 1 maxlen maxlen length length result result wrapchar wrapchar
+ if {$maxlen && $length >= $maxlen} {
+ append result $wrapchar
+ set length 0
+ }
+ append result $x
+ incr length
+ return
+ }
+
+ # ::base64::decode --
+ #
+ # Base64 decode a given string.
+ #
+ # Arguments:
+ # string The string to decode. Characters not in the base64
+ # alphabet are ignored (e.g., newlines)
+ #
+ # Results:
+ # The decoded value.
+
+ proc ::base64::decode {string} {
+ if {[string length $string] == 0} {return ""}
+
+ set base64 $::base64::base64
+ set output "" ; # Fix for [Bug 821126]
+
+ binary scan $string c* X
+ foreach x $X {
+ set bits [lindex $base64 $x]
+ if {$bits >= 0} {
+ if {[llength [lappend nums $bits]] == 4} {
+ foreach {v w z y} $nums break
+ set a [expr {($v << 2) | ($w >> 4)}]
+ set b [expr {(($w & 0xF) << 4) | ($z >> 2)}]
+ set c [expr {(($z & 0x3) << 6) | $y}]
+ append output [binary format ccc $a $b $c]
+ set nums {}
+ }
+ } elseif {$bits == -1} {
+ # = indicates end of data. Output whatever chars are left.
+ # The encoding algorithm dictates that we can only have 1 or 2
+ # padding characters. If x=={}, we must (*) have 12 bits of input
+ # (enough for 1 8-bit output). If x!={}, we have 18 bits of
+ # input (enough for 2 8-bit outputs).
+ #
+ # (*) If we don't then the input is broken (bug 2976290).
+
+ foreach {v w z} $nums break
+
+ # Bug 2976290
+ if {$w == {}} {
+ return -code error "Not enough data to process padding"
+ }
+
+ set a [expr {($v << 2) | (($w & 0x30) >> 4)}]
+ if {$z == {}} {
+ append output [binary format c $a ]
+ } else {
+ set b [expr {(($w & 0xF) << 4) | (($z & 0x3C) >> 2)}]
+ append output [binary format cc $a $b]
+ }
+ break
+ } else {
+ # RFC 2045 says that line breaks and other characters not part
+ # of the Base64 alphabet must be ignored, and that the decoder
+ # can optionally emit a warning or reject the message. We opt
+ # not to do so, but to just ignore the character.
+ continue
+ }
+ }
+ return $output
+ }
+}
+
+package provide base64 2.4.2
diff --git a/tcllib/modules/base64/base64.test b/tcllib/modules/base64/base64.test
new file mode 100644
index 0000000..926a16d
--- /dev/null
+++ b/tcllib/modules/base64/base64.test
@@ -0,0 +1,162 @@
+# Tests for the base64 module. -*- tcl -*-
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# All rights reserved.
+#
+# RCS: @(#) $Id: base64.test,v 1.17 2011/11/09 04:31:24 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.2
+testsNeedTcltest 1.0
+
+testing {
+ useLocal base64.tcl base64
+}
+
+# -------------------------------------------------------------------------
+
+if {[catch {package present Trf}]} {
+ puts "> pure Tcl"
+ tcltest::testConstraint trf 0
+} else {
+ puts "> Trf based"
+ tcltest::testConstraint trf 1
+}
+
+# -------------------------------------------------------------------------
+
+test base64-1.1 {base64::encode} {
+ base64::encode "this is a test\n"
+} "dGhpcyBpcyBhIHRlc3QK"
+test base64-1.2 {base64::encode wraps lines at 76 characters} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ base64::encode $str
+} "VGhlIHNob3J0IHJlZCBmb3ggcmFuIHF1aWNrbHkgdGhyb3VnaCB0aGUgZ3JlZW4gZmllbGQgYW5k
+IGp1bXBlZCBvdmVyIHRoZSB0YWxsIGJyb3duIGJlYXIK"
+test base64-1.3 {base64::encode with wrap length set to 60} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ base64::encode -maxlen 60 $str
+} "VGhlIHNob3J0IHJlZCBmb3ggcmFuIHF1aWNrbHkgdGhyb3VnaCB0aGUgZ3Jl
+ZW4gZmllbGQgYW5kIGp1bXBlZCBvdmVyIHRoZSB0YWxsIGJyb3duIGJlYXIK"
+test base64-1.4 {base64::encode with wrap length set to 0} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ base64::encode -maxlen 0 $str
+} "VGhlIHNob3J0IHJlZCBmb3ggcmFuIHF1aWNrbHkgdGhyb3VnaCB0aGUgZ3JlZW4gZmllbGQgYW5kIGp1bXBlZCBvdmVyIHRoZSB0YWxsIGJyb3duIGJlYXIK"
+test base64-1.5 {base64::encode with wrap length set to 76, wrapchar to newline+space} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ base64::encode -maxlen 76 -wrapchar "\n " $str
+} "VGhlIHNob3J0IHJlZCBmb3ggcmFuIHF1aWNrbHkgdGhyb3VnaCB0aGUgZ3JlZW4gZmllbGQgYW5k
+ IGp1bXBlZCBvdmVyIHRoZSB0YWxsIGJyb3duIGJlYXIK"
+test base64-1.6 {base64::encode, errors} {
+ list [catch {base64::encode} msg] $msg
+} [list 1 "wrong # args: should be \"base64::encode ?-maxlen maxlen? ?-wrapchar wrapchar? string\""]
+test base64-1.7 {base64::encode, errors} {
+ list [catch {base64::encode -maxlen foo} msg] $msg
+} [list 1 "value for \"-maxlen\" missing"]
+test base64-1.8 {base64::encode, errors} {
+ list [catch {base64::encode -maxlen foo bar} msg] $msg
+} [list 1 "expected integer but got \"foo\""]
+test base64-1.9 {base64::encode, errors} {
+ list [catch {base64::encode -maxlen foo -wrapchar bar} msg] $msg
+} [list 1 "value for \"-wrapchar\" missing"]
+test base64-1.10 {base64::encode, errors} {
+ list [catch {base64::encode -foo bar} msg] $msg
+} [list 1 "unknown option \"-foo\": must be -maxlen or -wrapchar"]
+test base64-1.11 {base64::encode with bogus wrap length (< 0)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ list [catch { base64::encode -maxlen -3 $str } msg] $msg
+} {1 {expected positive integer but got "-3"}}
+test base64-1.12 {base64::encode with bogus wrap length (non-numeric)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ list [catch { base64::encode -maxlen foo $str } msg] $msg
+} {1 {expected integer but got "foo"}}
+test base64-1.13 {base64::encode with bogus wrap length (non-integer)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ list [catch { base64::encode -maxlen 1.5 $str } msg] $msg
+} {1 {expected integer but got "1.5"}}
+test base64-1.14 {base64::encode with wrap length set to 20} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ base64::encode -maxlen 20 $str
+} "VGhlIHNob3J0IHJlZCBm
+b3ggcmFuIHF1aWNrbHkg
+dGhyb3VnaCB0aGUgZ3Jl
+ZW4gZmllbGQgYW5kIGp1
+bXBlZCBvdmVyIHRoZSB0
+YWxsIGJyb3duIGJlYXIK"
+test base64-1.15 {base64::encode with wrap length set to 23 (prime)} {
+ set str "The short red fox ran quickly through the green field "
+ append str "and jumped over the tall brown bear\n"
+ base64::encode -maxlen 23 $str
+} "VGhlIHNob3J0IHJlZCBmb3g
+gcmFuIHF1aWNrbHkgdGhyb3
+VnaCB0aGUgZ3JlZW4gZmllb
+GQgYW5kIGp1bXBlZCBvdmVy
+IHRoZSB0YWxsIGJyb3duIGJ
+lYXIK"
+
+
+test base64-2.1 {base64::decode} {
+ base64::decode "dGhpcyBpcyBhIHRlc3QK"
+} "this is a test\n"
+test base64-2.2 {base64::decode ignores newlines} {
+ set str "VGhlIHNob3J0IHJlZCBmb3ggcmFuIHF1aWNrbHkgdGhyb3VnaCB0aGUgZ3Jl\n"
+ append str "ZW4gZmllbGQgYW5kIGp1bXBlZCBvdmVyIHRoZSB0YWxsIGJyb3duIGJlYXIK"
+ base64::decode $str
+} "The short red fox ran quickly through the green field and jumped over the tall brown bear\n"
+test base64-2.3 {base64::decode handles equal sign padding} {
+ # decode the encoding of a string that will be padded in the encoding with
+ # one padding char
+ base64::decode [base64::encode "01234"]
+} "01234"
+test base64-2.4 {base64::decode handles equal sign padding} {
+ # decode the encoding of a string that will be padded in the encoding with
+ # two padding chars
+ base64::decode [base64::encode "0123"]
+} "0123"
+
+
+test base64-2.5 {base64::decode} {
+ base64::decode ""
+} ""
+test base64-2.6 {base64::decode} {
+ base64::decode " "
+} ""
+
+
+test base64-3.1 {base64 identity test} {
+ base64::decode [base64::encode "this is a test"]
+} "this is a test"
+test base64-3.2 {base64 identity test} {
+ # This test fails on version 1.5 because of the format %04x bug
+ # when handling the last characters
+ set x \f\xee
+ set y [base64::decode [base64::encode $x]]
+ string compare $x $y
+} 0
+
+# For trf a known bug.
+test base64-4.0 {base64 -- sf bug 2976290} {!trf} {
+ list [catch {
+ ::base64::decode s=GQMRAk5WXhsABh0NEx4RXBocBVgBHQMXHRgEFltMQENQXEFOExJVQ0RAQERUQ0dAEhYEExVIRRVVFENWKxMKABsPGBI6LRoYLhsEFhsXGFkXEwZXGQMIHg==
+ } msg] $msg
+} {1 {Not enough data to process padding}}
+
+testsuiteCleanup
+return
diff --git a/tcllib/modules/base64/base64c.tcl b/tcllib/modules/base64/base64c.tcl
new file mode 100644
index 0000000..29e501d
--- /dev/null
+++ b/tcllib/modules/base64/base64c.tcl
@@ -0,0 +1,19 @@
+# base64c - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# This package is a place-holder for the critcl enhanced code present in
+# the tcllib base64 module.
+#
+# Normally this code will become part of the tcllibc library.
+#
+
+# @sak notprovided base64c
+package require critcl
+package provide base64c 0.1.0
+
+namespace eval ::base64c {
+ variable base64c_rcsid {$Id: base64c.tcl,v 1.5 2008/03/25 07:15:35 andreas_kupries Exp $}
+
+ critcl::ccode {
+ /* no code required in this file */
+ }
+}
diff --git a/tcllib/modules/base64/pkgIndex.tcl b/tcllib/modules/base64/pkgIndex.tcl
new file mode 100644
index 0000000..c23b090
--- /dev/null
+++ b/tcllib/modules/base64/pkgIndex.tcl
@@ -0,0 +1,5 @@
+if {![package vsatisfies [package provide Tcl] 8.2]} {return}
+package ifneeded base64 2.4.2 [list source [file join $dir base64.tcl]]
+package ifneeded uuencode 1.1.5 [list source [file join $dir uuencode.tcl]]
+package ifneeded yencode 1.1.3 [list source [file join $dir yencode.tcl]]
+package ifneeded ascii85 1.0 [list source [file join $dir ascii85.tcl]]
diff --git a/tcllib/modules/base64/uuencode.bench b/tcllib/modules/base64/uuencode.bench
new file mode 100644
index 0000000..714cfe9
--- /dev/null
+++ b/tcllib/modules/base64/uuencode.bench
@@ -0,0 +1,46 @@
+# -*- tcl -*-
+# Tcl Benchmark File
+#
+# This file contains a number of benchmarks for the 'uuencode' module.
+# This allow developers to monitor/gauge/track package performance.
+#
+# (c) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+# We need at least version 8.2 for the package and thus the
+# benchmarks.
+
+if {![package vsatisfies [package provide Tcl] 8.2]} {
+ return
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Setting up the environment ...
+
+package forget uuencode
+catch {namespace delete ::uuencode}
+source [file join [file dirname [info script]] uuencode.tcl]
+
+# ### ### ### ######### ######### ######### ###########################
+## Benchmarks.
+
+
+foreach n {10 100 1000 10000} {
+ bench -desc "UUENCODE encode ${n}X" -pre {
+ set str [string repeat X $n]
+ } -body {
+ uuencode::encode $str
+ } -post {
+ unset str
+ }
+
+ bench -desc "UUENCODE decode ${n}X" -pre {
+ set str [uuencode::encode [string repeat X $n]]
+ } -body {
+ uuencode::decode $str
+ } -post {
+ unset str
+ }
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Complete
diff --git a/tcllib/modules/base64/uuencode.man b/tcllib/modules/base64/uuencode.man
new file mode 100644
index 0000000..c701a56
--- /dev/null
+++ b/tcllib/modules/base64/uuencode.man
@@ -0,0 +1,97 @@
+[manpage_begin uuencode n 1.1.4]
+[keywords encoding]
+[keywords uuencode]
+[copyright {2002, Pat Thoyts}]
+[moddesc {Text encoding & decoding binary data}]
+[titledesc {UU-encode/decode binary data}]
+[category {Text processing}]
+[require Tcl 8]
+[require uuencode [opt 1.1.4]]
+[description]
+[para]
+
+This package provides a Tcl-only implementation of the
+[syscmd uuencode(1)] and [syscmd uudecode(1)] commands. This encoding
+packs binary data into printable ASCII characters.
+
+[list_begin definitions]
+
+[call [cmd ::uuencode::encode] [arg string]]
+
+returns the uuencoded data. This will encode all the data passed in
+even if this is longer than the uuencode maximum line length. If the
+number of input bytes is not a multiple of 3 then additional 0 bytes
+are added to pad the string.
+
+[call [cmd ::uuencode::decode] [arg string]]
+
+Decodes the given encoded data. This will return any padding
+characters as well and it is the callers responsibility to deal with
+handling the actual length of the encoded data. (see uuencode).
+
+[call [cmd ::uuencode::uuencode] [opt "[option -name] [arg string]"] [opt "[option -mode] [arg octal]"] "([option -file] [arg filename] | [opt [option --]] [arg string])"]
+
+[call [cmd ::uuencode::uudecode] "([option -file] [arg filename] | [opt [option --]] [arg string])"]
+
+UUDecode a file or block of data. A file may contain more than one
+embedded file so the result is a list where each element is a three
+element list of filename, mode value and data.
+
+[list_end]
+
+[section OPTIONS]
+
+[list_begin definitions]
+
+[def "-filename name"]
+
+Cause the uuencode or uudecode commands to read their data from the
+named file rather that taking a string parameter.
+
+[def "-name string"]
+
+The uuencoded data header line contains the suggested file name to be
+used when unpacking the data. Use this option to change this from the
+default of "data.dat".
+
+[def "-mode octal"]
+
+The uuencoded data header line contains a suggested permissions bit
+pattern expressed as an octal string. To change the default of 0644
+you can set this option. For instance, 0755 would be suitable for an
+executable. See [syscmd chmod(1)].
+
+[list_end]
+
+[section EXAMPLES]
+
+[para]
+[example {
+% set d [uuencode::encode "Hello World!"]
+2&5L;&\\@5V]R;&0A
+}]
+
+[para]
+[example {
+% uuencode::uudecode $d
+Hello World!
+}]
+
+[para]
+[example {
+% set d [uuencode::uuencode -name hello.txt "Hello World"]
+begin 644 hello.txt
++2&5L;&\@5V]R;&0`
+`
+end
+}]
+
+[para]
+[example {
+% uuencode::uudecode $d
+{hello.txt 644 {Hello World}}
+}]
+
+[vset CATEGORY base64]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/base64/uuencode.pcx b/tcllib/modules/base64/uuencode.pcx
new file mode 100644
index 0000000..13e122d
--- /dev/null
+++ b/tcllib/modules/base64/uuencode.pcx
@@ -0,0 +1,74 @@
+# -*- tcl -*- uuencode.pcx
+# Syntax of the commands provided by package uuencode.
+#
+# For use by TclDevKit's static syntax checker.
+# See http://www.activestate.com/solutions/tcl/
+# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
+# for the documentation describing the format of the code contained in this file
+#
+
+package require pcx
+pcx::register uuencode
+pcx::tcldep 1.1.4 needs tcl 8.2
+
+namespace eval ::uuencode {}
+
+# Using the indirections below looks to be quite pointless, given that
+# they simply substitute the commands for others. I am doing this for
+# two reasons.
+
+# First, the rules coming after become self-commenting, i.e. a
+# maintainer can immediately see what an argument is supposed to be,
+# instead of having to search elsewhere (like the documentation and
+# implementation). In this manner our definitions here are a type of
+# semantic markup.
+
+# The second reason is that while we have no special checks now we
+# cannot be sure if such will (have to) be added in the future. With
+# all checking routed through our definitions we now already have the
+# basic infrastructure (i.e. hooks) in place in which we can easily
+# add any new checks by simply redefining the relevant command, and
+# all the rules update on their own. Mostly. This should cover 90% of
+# the cases. Sometimes new checks will require to create deeper
+# distinctions between different calls of the same thing. For such we
+# may have to update the rules as well, to provide the necessary
+# information to the checker.
+
+interp alias {} uuencode::checkMode {} checkWord ; #
+interp alias {} uuencode::checkDstFilename {} checkWord ; #
+interp alias {} uuencode::checkData {} checkWord ; #
+
+#pcx::message FOO {... text ...} type
+#pcx::scan <VERSION> <NAME> <RULE>
+
+pcx::check 1.1.4 std ::uuencode::uudecode \
+ {checkConstrained {checkSimpleArgs 1 -1 {
+ {checkSwitches 1 {
+ {-filename {checkSetConstraint hasfilename checkFileName}}
+ --
+ } {checkConstraint {
+ {hasfilename {checkSimpleArgs 0 0 {}}}
+ {!hasfilename {checkSimpleArgs 1 1 {
+ uuencode::checkData
+ }}}
+ } {}}}
+ }}}
+# TODO: Limit -mode to a octal numbers (file permissions)
+pcx::check 1.1.4 std ::uuencode::uuencode \
+ {checkConstrained {checkSimpleArgs 1 -1 {
+ {checkSwitches 1 {
+ {-filename {checkSetConstraint hasfilename checkFileName}}
+ {-mode uuencode::checkMode}
+ {-name uuencode::checkDstFilename}
+ --
+ } {checkConstraint {
+ {hasfilename {checkSimpleArgs 0 0 {}}}
+ {!hasfilename {checkSimpleArgs 1 1 {
+ uuencode::checkData
+ }}}
+ } {}}}
+ }}}
+
+# Initialization via pcx::init.
+# Use a ::uuencode::init procedure for non-standard initialization.
+pcx::complete
diff --git a/tcllib/modules/base64/uuencode.tcl b/tcllib/modules/base64/uuencode.tcl
new file mode 100644
index 0000000..e0e9862
--- /dev/null
+++ b/tcllib/modules/base64/uuencode.tcl
@@ -0,0 +1,335 @@
+# uuencode - Copyright (C) 2002 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# Provide a Tcl only implementation of uuencode and uudecode.
+#
+# -------------------------------------------------------------------------
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# -------------------------------------------------------------------------
+
+package require Tcl 8.2; # tcl minimum version
+
+# Try and get some compiled helper package.
+if {[catch {package require tcllibc}]} {
+ catch {package require Trf}
+}
+
+namespace eval ::uuencode {
+ namespace export encode decode uuencode uudecode
+}
+
+proc ::uuencode::Enc {c} {
+ return [format %c [expr {($c != 0) ? (($c & 0x3f) + 0x20) : 0x60}]]
+}
+
+proc ::uuencode::Encode {s} {
+ set r {}
+ binary scan $s c* d
+ foreach {c1 c2 c3} $d {
+ if {$c1 == {}} {set c1 0}
+ if {$c2 == {}} {set c2 0}
+ if {$c3 == {}} {set c3 0}
+ append r [Enc [expr {$c1 >> 2}]]
+ append r [Enc [expr {(($c1 << 4) & 060) | (($c2 >> 4) & 017)}]]
+ append r [Enc [expr {(($c2 << 2) & 074) | (($c3 >> 6) & 003)}]]
+ append r [Enc [expr {($c3 & 077)}]]
+ }
+ return $r
+}
+
+
+proc ::uuencode::Decode {s} {
+ if {[string length $s] == 0} {return ""}
+ set r {}
+ binary scan [pad $s] c* d
+
+ foreach {c0 c1 c2 c3} $d {
+ append r [format %c [expr {((($c0-0x20)&0x3F) << 2) & 0xFF
+ | ((($c1-0x20)&0x3F) >> 4) & 0xFF}]]
+ append r [format %c [expr {((($c1-0x20)&0x3F) << 4) & 0xFF
+ | ((($c2-0x20)&0x3F) >> 2) & 0xFF}]]
+ append r [format %c [expr {((($c2-0x20)&0x3F) << 6) & 0xFF
+ | (($c3-0x20)&0x3F) & 0xFF}]]
+ }
+ return $r
+}
+
+# -------------------------------------------------------------------------
+# C coded version of the Encode/Decode functions for base64c package.
+# -------------------------------------------------------------------------
+if {[package provide critcl] != {}} {
+ namespace eval ::uuencode {
+ critcl::ccode {
+ #include <string.h>
+ static unsigned char Enc(unsigned char c) {
+ return (c != 0) ? ((c & 0x3f) + 0x20) : 0x60;
+ }
+ }
+ critcl::ccommand CEncode {dummy interp objc objv} {
+ Tcl_Obj *inputPtr, *resultPtr;
+ int len, rlen, xtra;
+ unsigned char *input, *p, *r;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "data");
+ return TCL_ERROR;
+ }
+
+ inputPtr = objv[1];
+ input = Tcl_GetByteArrayFromObj(inputPtr, &len);
+ if ((xtra = (3 - (len % 3))) != 3) {
+ if (Tcl_IsShared(inputPtr))
+ inputPtr = Tcl_DuplicateObj(inputPtr);
+ input = Tcl_SetByteArrayLength(inputPtr, len + xtra);
+ memset(input + len, 0, xtra);
+ len += xtra;
+ }
+
+ rlen = (len / 3) * 4;
+ resultPtr = Tcl_NewObj();
+ r = Tcl_SetByteArrayLength(resultPtr, rlen);
+ memset(r, 0, rlen);
+
+ for (p = input; p < input + len; p += 3) {
+ char a, b, c;
+ a = *p; b = *(p+1), c = *(p+2);
+ *r++ = Enc(a >> 2);
+ *r++ = Enc(((a << 4) & 060) | ((b >> 4) & 017));
+ *r++ = Enc(((b << 2) & 074) | ((c >> 6) & 003));
+ *r++ = Enc(c & 077);
+ }
+ Tcl_SetObjResult(interp, resultPtr);
+ return TCL_OK;
+ }
+
+ critcl::ccommand CDecode {dummy interp objc objv} {
+ Tcl_Obj *inputPtr, *resultPtr;
+ int len, rlen, xtra;
+ unsigned char *input, *p, *r;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "data");
+ return TCL_ERROR;
+ }
+
+ /* if input is not mod 4, extend it with nuls */
+ inputPtr = objv[1];
+ input = Tcl_GetByteArrayFromObj(inputPtr, &len);
+ if ((xtra = (4 - (len % 4))) != 4) {
+ if (Tcl_IsShared(inputPtr))
+ inputPtr = Tcl_DuplicateObj(inputPtr);
+ input = Tcl_SetByteArrayLength(inputPtr, len + xtra);
+ memset(input + len, 0, xtra);
+ len += xtra;
+ }
+
+ /* output will be 1/3 smaller than input and a multiple of 3 */
+ rlen = (len / 4) * 3;
+ resultPtr = Tcl_NewObj();
+ r = Tcl_SetByteArrayLength(resultPtr, rlen);
+ memset(r, 0, rlen);
+
+ for (p = input; p < input + len; p += 4) {
+ char a, b, c, d;
+ a = *p; b = *(p+1), c = *(p+2), d = *(p+3);
+ *r++ = (((a - 0x20) & 0x3f) << 2) | (((b - 0x20) & 0x3f) >> 4);
+ *r++ = (((b - 0x20) & 0x3f) << 4) | (((c - 0x20) & 0x3f) >> 2);
+ *r++ = (((c - 0x20) & 0x3f) << 6) | (((d - 0x20) & 0x3f) );
+ }
+ Tcl_SetObjResult(interp, resultPtr);
+ return TCL_OK;
+ }
+ }
+}
+
+# -------------------------------------------------------------------------
+
+# Description:
+# Permit more tolerant decoding of invalid input strings by padding to
+# a multiple of 4 bytes with nulls.
+# Result:
+# Returns the input string - possibly padded with uuencoded null chars.
+#
+proc ::uuencode::pad {s} {
+ if {[set mod [expr {[string length $s] % 4}]] != 0} {
+ append s [string repeat "`" [expr {4 - $mod}]]
+ }
+ return $s
+}
+
+# -------------------------------------------------------------------------
+
+# If the Trf package is available then we shall use this by default but the
+# Tcllib implementations are always visible if needed (ie: for testing)
+if {[info commands ::uuencode::CDecode] != {}} {
+ # tcllib critcl package
+ interp alias {} ::uuencode::encode {} ::uuencode::CEncode
+ interp alias {} ::uuencode::decode {} ::uuencode::CDecode
+} elseif {[package provide Trf] != {}} {
+ proc ::uuencode::encode {s} {
+ return [::uuencode -mode encode -- $s]
+ }
+ proc ::uuencode::decode {s} {
+ return [::uuencode -mode decode -- [pad $s]]
+ }
+} else {
+ # pure-tcl then
+ interp alias {} ::uuencode::encode {} ::uuencode::Encode
+ interp alias {} ::uuencode::decode {} ::uuencode::Decode
+}
+
+# -------------------------------------------------------------------------
+
+proc ::uuencode::uuencode {args} {
+ array set opts {mode 0644 filename {} name {}}
+ set wrongargs "wrong \# args: should be\
+ \"uuencode ?-name string? ?-mode octal?\
+ (-file filename | ?--? string)\""
+ while {[string match -* [lindex $args 0]]} {
+ switch -glob -- [lindex $args 0] {
+ -f* {
+ if {[llength $args] < 2} {
+ return -code error $wrongargs
+ }
+ set opts(filename) [lindex $args 1]
+ set args [lreplace $args 0 0]
+ }
+ -m* {
+ if {[llength $args] < 2} {
+ return -code error $wrongargs
+ }
+ set opts(mode) [lindex $args 1]
+ set args [lreplace $args 0 0]
+ }
+ -n* {
+ if {[llength $args] < 2} {
+ return -code error $wrongargs
+ }
+ set opts(name) [lindex $args 1]
+ set args [lreplace $args 0 0]
+ }
+ -- {
+ set args [lreplace $args 0 0]
+ break
+ }
+ default {
+ return -code error "bad option [lindex $args 0]:\
+ must be -file, -mode, or -name"
+ }
+ }
+ set args [lreplace $args 0 0]
+ }
+
+ if {$opts(name) == {}} {
+ set opts(name) $opts(filename)
+ }
+ if {$opts(name) == {}} {
+ set opts(name) "data.dat"
+ }
+
+ if {$opts(filename) != {}} {
+ set f [open $opts(filename) r]
+ fconfigure $f -translation binary
+ set data [read $f]
+ close $f
+ } else {
+ if {[llength $args] != 1} {
+ return -code error $wrongargs
+ }
+ set data [lindex $args 0]
+ }
+
+ set r {}
+ append r [format "begin %o %s" $opts(mode) $opts(name)] "\n"
+ for {set n 0} {$n < [string length $data]} {incr n 45} {
+ set s [string range $data $n [expr {$n + 44}]]
+ append r [Enc [string length $s]]
+ append r [encode $s] "\n"
+ }
+ append r "`\nend"
+ return $r
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# Perform uudecoding of a file or data. A file may contain more than one
+# encoded data section so the result is a list where each element is a
+# three element list of the provided filename, the suggested mode and the
+# data itself.
+#
+proc ::uuencode::uudecode {args} {
+ array set opts {mode 0644 filename {}}
+ set wrongargs "wrong \# args: should be \"uudecode (-file filename | ?--? string)\""
+ while {[string match -* [lindex $args 0]]} {
+ switch -glob -- [lindex $args 0] {
+ -f* {
+ if {[llength $args] < 2} {
+ return -code error $wrongargs
+ }
+ set opts(filename) [lindex $args 1]
+ set args [lreplace $args 0 0]
+ }
+ -- {
+ set args [lreplace $args 0 0]
+ break
+ }
+ default {
+ return -code error "bad option [lindex $args 0]:\
+ must be -file"
+ }
+ }
+ set args [lreplace $args 0 0]
+ }
+
+ if {$opts(filename) != {}} {
+ set f [open $opts(filename) r]
+ set data [read $f]
+ close $f
+ } else {
+ if {[llength $args] != 1} {
+ return -code error $wrongargs
+ }
+ set data [lindex $args 0]
+ }
+
+ set state false
+ set result {}
+
+ foreach {line} [split $data "\n"] {
+ switch -exact -- $state {
+ false {
+ if {[regexp {^begin ([0-7]+) ([^\s]*)} $line \
+ -> opts(mode) opts(name)]} {
+ set state true
+ set r {}
+ }
+ }
+
+ true {
+ if {[string match "end" $line]} {
+ set state false
+ lappend result [list $opts(name) $opts(mode) $r]
+ } else {
+ scan $line %c c
+ set n [expr {($c - 0x21)}]
+ append r [string range \
+ [decode [string range $line 1 end]] 0 $n]
+ }
+ }
+ }
+ }
+
+ return $result
+}
+
+# -------------------------------------------------------------------------
+
+package provide uuencode 1.1.5
+
+# -------------------------------------------------------------------------
+#
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
+
diff --git a/tcllib/modules/base64/uuencode.test b/tcllib/modules/base64/uuencode.test
new file mode 100644
index 0000000..1e968da
--- /dev/null
+++ b/tcllib/modules/base64/uuencode.test
@@ -0,0 +1,193 @@
+# uuencode.test - Copyright (C) 2002 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# Tests for the Tcllib uuencode package
+#
+# -------------------------------------------------------------------------
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# -------------------------------------------------------------------------
+# RCS: @(#) $Id: uuencode.test,v 1.15 2008/12/12 04:57:46 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.2
+testsNeedTcltest 1.0
+
+testing {
+ useTcllibC
+ useLocalKeep uuencode.tcl uuencode
+}
+
+# -------------------------------------------------------------------------
+
+set trf 0
+if {[llength [info commands ::uuencode::CEncode]]} {
+ puts "> critcl based"
+} elseif {[package provide Trf] != {}} {
+ puts "> Trf based"
+ set trf 1
+} else {
+ puts "> pure tcl"
+}
+
+package require log
+log::lvSuppress notice
+
+# -------------------------------------------------------------------------
+
+test uuencode-1.0 {encode string} {
+ catch {::uuencode::encode ABC} result
+ set result
+} "04)#"
+
+test uuencode-1.1 {decode string} {
+ catch {::uuencode::decode "04)#"} result
+ set result
+} "ABC"
+
+test uuencode-1.2 {encode longer string} {
+ catch {::uuencode::encode [string repeat x 102]} result
+ set result
+} [string repeat ">'AX" 34]
+
+test uuencode-1.3 {decode longer string} {
+ catch {::uuencode::decode [string repeat ">'AX" 34]} result
+ set result
+} [string repeat x 102]
+
+# Trf uses a different padding character.
+if {!$trf} {
+ # critcl / pure tcl based
+ set testdata {begin 644 data.dat
+75&AE(&-A="!S870@;VX@=&AE(&UA="X`
+`
+end}
+} else {
+ set testdata {begin 644 data.dat
+75&AE(&-A="!S870@;VX@=&AE(&UA="X~
+`
+end}
+}
+
+test uuencode-1.4 {uuencode string} {
+ catch {::uuencode::uuencode "The cat sat on the mat."} result
+ set result
+} $testdata
+
+test uuencode-1.5 {uudecode string} {
+ catch {::uuencode::uudecode $testdata} result
+ set result
+} [list [list data.dat 644 "The cat sat on the mat."]]
+
+test uuencode-1.6 {encode dash-string} {
+ catch {::uuencode::encode -BC} result
+ set result
+} "+4)#"
+
+test uuencode-1.7 {decode dash-string} {
+ catch {::uuencode::decode "-4)#"} result
+ set result
+} "5BC"
+
+# -------------------------------------------------------------------------
+
+set testdata [list \
+ "begin 644 data.dat" \
+ "75&AE(&-A=\"!S870@;VX@=&AE(&UA=\"X" \
+ "`" \
+ "end" ]
+
+test uuencode-2.1 {uudecode unpadded lines} {
+ catch {::uuencode::uudecode [join $testdata "\n"]} result
+ set result
+} [list [list data.dat 644 "The cat sat on the mat."]]
+
+test uuencode-2.2 {uudecode DOS line endings} {
+ set f [open uuencode.test.data w]
+ fconfigure $f -translation binary
+ puts -nonewline $f [join $testdata "\r\n"]
+ close $f
+ catch {::uuencode::uudecode -file uuencode.test.data} result
+ set result
+} [list [list data.dat 644 "The cat sat on the mat."]]
+
+foreach {n in out} {
+ 0 a {80``}
+ 1 abc {86)C}
+ 2 \0 {````}
+ 3 "\r\n\t" {#0H)}
+ 4 "hello world" {:&5L;&\@=V]R;&0`}
+} {
+ test uuencode-3.$n {check the pure tcl encoder} {
+ list [catch {::uuencode::Encode $in} r] $r
+ } [list 0 $out]
+}
+
+# -------------------------------------------------------------------------
+
+test uuencode-4.0 {encode bad args} {
+ catch {::uuencode::uuencode -bogus} result
+ set result
+} {bad option -bogus: must be -file, -mode, or -name}
+
+test uuencode-4.1 {encode wrong#args} {
+ catch {::uuencode::uuencode -file} result
+ set result
+} {wrong # args: should be "uuencode ?-name string? ?-mode octal? (-file filename | ?--? string)"}
+
+test uuencode-4.2 {encode wrong#args} {
+ catch {::uuencode::uuencode -name} result
+ set result
+} {wrong # args: should be "uuencode ?-name string? ?-mode octal? (-file filename | ?--? string)"}
+
+test uuencode-4.3 {encode wrong#args} {
+ catch {::uuencode::uuencode -mode} result
+ set result
+} {wrong # args: should be "uuencode ?-name string? ?-mode octal? (-file filename | ?--? string)"}
+
+test uuencode-4.4 {encode wrong#args} {
+ catch {::uuencode::uuencode -mode 1} result
+ set result
+} {wrong # args: should be "uuencode ?-name string? ?-mode octal? (-file filename | ?--? string)"}
+
+test uuencode-4.5 {encode wrong#args} {
+ catch {::uuencode::uuencode -name foo} result
+ set result
+} {wrong # args: should be "uuencode ?-name string? ?-mode octal? (-file filename | ?--? string)"}
+
+test uuencode-4.6 {encode wrong#args} {
+ catch {::uuencode::uuencode --} result
+ set result
+} {wrong # args: should be "uuencode ?-name string? ?-mode octal? (-file filename | ?--? string)"}
+
+
+
+test uuencode-5.0 {decode bad args} {
+ catch {::uuencode::uudecode -bogus} result
+ set result
+} {bad option -bogus: must be -file}
+
+test uuencode-5.1 {decode wrong#args} {
+ catch {::uuencode::uudecode -file} result
+ set result
+} {wrong # args: should be "uudecode (-file filename | ?--? string)"}
+
+test uuencode-5.2 {decode wrong#args} {
+ catch {::uuencode::uudecode --} result
+ set result
+} {wrong # args: should be "uudecode (-file filename | ?--? string)"}
+
+
+# -------------------------------------------------------------------------
+
+file delete -force uuencode.test.data
+testsuiteCleanup
+
+# Local Variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
diff --git a/tcllib/modules/base64/yencode.bench b/tcllib/modules/base64/yencode.bench
new file mode 100644
index 0000000..706acb5
--- /dev/null
+++ b/tcllib/modules/base64/yencode.bench
@@ -0,0 +1,46 @@
+# -*- tcl -*-
+# Tcl Benchmark File
+#
+# This file contains a number of benchmarks for the 'yencode' module.
+# This allow developers to monitor/gauge/track package performance.
+#
+# (c) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+# We need at least version 8.2 for the package and thus the
+# benchmarks.
+
+if {![package vsatisfies [package provide Tcl] 8.2]} {
+ return
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Setting up the environment ...
+
+package forget yencode
+catch {namespace delete ::yencode}
+source [file join [file dirname [info script]] yencode.tcl]
+
+# ### ### ### ######### ######### ######### ###########################
+## Benchmarks.
+
+
+foreach n {10 100 1000 10000} {
+ bench -desc "YENCODE encode ${n}X" -pre {
+ set str [string repeat X $n]
+ } -body {
+ yencode::encode $str
+ } -post {
+ unset str
+ }
+
+ bench -desc "YENCODE decode ${n}X" -pre {
+ set str [yencode::encode [string repeat X $n]]
+ } -body {
+ yencode::decode $str
+ } -post {
+ unset str
+ }
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Complete
diff --git a/tcllib/modules/base64/yencode.man b/tcllib/modules/base64/yencode.man
new file mode 100644
index 0000000..575d441
--- /dev/null
+++ b/tcllib/modules/base64/yencode.man
@@ -0,0 +1,96 @@
+[manpage_begin yencode n 1.1.2]
+[keywords encoding]
+[keywords ydecode]
+[keywords yEnc]
+[keywords yencode]
+[copyright {2002, Pat Thoyts}]
+[moddesc {Text encoding & decoding binary data}]
+[titledesc {Y-encode/decode binary data}]
+[category {Text processing}]
+[require Tcl 8.2]
+[require yencode [opt 1.1.2]]
+[description]
+[para]
+
+This package provides a Tcl-only implementation of the yEnc file
+encoding. This is a recently introduced method of encoding binary
+files for transmission through Usenet. This encoding packs binary data
+into a format that requires an 8-bit clean transmission layer but that
+escapes characters special to the [term NNTP] posting protocols. See
+[uri http://www.yenc.org/] for details concerning the algorithm.
+
+[list_begin definitions]
+
+[call [cmd ::yencode::encode] [arg string]]
+
+returns the yEnc encoded data.
+
+[call [cmd ::yencode::decode] [arg "string"]]
+
+Decodes the given yEnc encoded data.
+
+[call [cmd ::yencode::yencode] \
+ [opt "[option -name] [arg string]"] \
+ [opt "[option -line] [arg integer]"] \
+ [opt "[option -crc32] [arg boolean]"] \
+ "([option -file] [arg filename] | [opt [option --]] [arg string])"]
+
+Encode a file or block of data.
+
+[call [cmd ::yencode::ydecode] \
+ "([option -file] [arg filename] | [opt [option --]] [arg string])"]
+
+Decode a file or block of data. A file may contain more than one
+embedded file so the result is a list where each element is a three
+element list of filename, file size and data.
+
+[list_end]
+
+[section OPTIONS]
+
+[list_begin definitions]
+
+[def "-filename name"]
+
+Cause the yencode or ydecode commands to read their data from the
+named file rather that taking a string parameter.
+
+[def "-name string"]
+
+The encoded data header line contains the suggested file name to be
+used when unpacking the data. Use this option to change this from the
+default of "data.dat".
+
+[def "-line integer"]
+
+The yencoded data header line contains records the line length used
+during the encoding. Use this option to select a line length other
+that the default of 128. Note that NNTP imposes a 1000 character line
+length limit and some gateways may have trouble with more than 255
+characters per line.
+
+[def "-crc32 boolean"]
+
+The yEnc specification recommends the inclusion of a cyclic redundancy
+check value in the footer. Use this option to change the default from
+[arg true] to [arg false].
+
+[list_end]
+
+[para]
+[example {
+% set d [yencode::yencode -file testfile.txt]
+=ybegin line=128 size=584 name=testfile.txt
+ -o- data not shown -o-
+=yend size=584 crc32=ded29f4f
+}]
+
+[section References]
+
+[list_begin enum]
+[enum] [uri http://www.yenc.org/yenc-draft.1.3.txt]
+[list_end]
+
+[vset CATEGORY base64]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/base64/yencode.pcx b/tcllib/modules/base64/yencode.pcx
new file mode 100644
index 0000000..e38499f
--- /dev/null
+++ b/tcllib/modules/base64/yencode.pcx
@@ -0,0 +1,78 @@
+# -*- tcl -*- yencode.pcx
+# Syntax of the commands provided by package yencode.
+#
+# For use by TclDevKit's static syntax checker.
+# See http://www.activestate.com/solutions/tcl/
+# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
+# for the documentation describing the format of the code contained in this file
+#
+
+package require pcx
+pcx::register yencode
+pcx::tcldep 1.1.1 needs tcl 8.2
+
+namespace eval ::yencode {}
+
+# Using the indirections below looks to be quite pointless, given that
+# they simply substitute the commands for others. I am doing this for
+# two reasons.
+
+# First, the rules coming after become self-commenting, i.e. a
+# maintainer can immediately see what an argument is supposed to be,
+# instead of having to search elsewhere (like the documentation and
+# implementation). In this manner our definitions here are a type of
+# semantic markup.
+
+# The second reason is that while we have no special checks now we
+# cannot be sure if such will (have to) be added in the future. With
+# all checking routed through our definitions we now already have the
+# basic infrastructure (i.e. hooks) in place in which we can easily
+# add any new checks by simply redefining the relevant command, and
+# all the rules update on their own. Mostly. This should cover 90% of
+# the cases. Sometimes new checks will require to create deeper
+# distinctions between different calls of the same thing. For such we
+# may have to update the rules as well, to provide the necessary
+# information to the checker.
+
+interp alias {} yencode::checkMode {} checkWord ; #
+interp alias {} yencode::checkDstFilename {} checkWord ; #
+interp alias {} yencode::checkData {} checkWord ; #
+interp alias {} yencode::checkLineLength {} checkInt ; #
+interp alias {} yencode::checkCrc32Flag {} checkBoolean ; #
+
+#pcx::message FOO {... text ...} type
+#pcx::scan <VERSION> <NAME> <RULE>
+
+pcx::check 1.1.1 std ::yencode::ydecode \
+ {checkConstrained {checkSimpleArgs 1 -1 {
+ {checkSwitches 1 {
+ {-filename {checkSetConstraint hasfilename checkFileName}}
+ --
+ } {checkConstraint {
+ {hasfilename {checkSimpleArgs 0 0 {}}}
+ {!hasfilename {checkSimpleArgs 1 1 {
+ yencode::checkData
+ }}}
+ } {}}}
+ }}}
+# TODO: Limit -mode to a octal numbers (file permissions)
+pcx::check 1.1.1 std ::yencode::yencode \
+ {checkConstrained {checkSimpleArgs 1 -1 {
+ {checkSwitches 1 {
+ {-crc32 yencode::checkCrc32Flag}
+ {-line yencode::checkLineLength}
+ {-mode yencode::checkMode}
+ {-name yencode::checkDstFilename}
+ {-filename {checkSetConstraint hasfilename checkFileName}}
+ --
+ } {checkConstraint {
+ {hasfilename {checkSimpleArgs 0 0 {}}}
+ {!hasfilename {checkSimpleArgs 1 1 {
+ yencode::checkData
+ }}}
+ } {}}}
+ }}}
+
+# Initialization via pcx::init.
+# Use a ::yencode::init procedure for non-standard initialization.
+pcx::complete
diff --git a/tcllib/modules/base64/yencode.tcl b/tcllib/modules/base64/yencode.tcl
new file mode 100644
index 0000000..5d2c035
--- /dev/null
+++ b/tcllib/modules/base64/yencode.tcl
@@ -0,0 +1,307 @@
+# yencode.tcl - Copyright (C) 2002 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# Provide a Tcl only implementation of yEnc encoding algorithm
+#
+# -------------------------------------------------------------------------
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# -------------------------------------------------------------------------
+
+# FUTURE: Rework to allow switching between the tcl/critcl implementations.
+
+package require Tcl 8.2; # tcl minimum version
+catch {package require crc32}; # tcllib 1.1
+catch {package require tcllibc}; # critcl enhancements for tcllib
+
+namespace eval ::yencode {
+ namespace export encode decode yencode ydecode
+}
+
+# -------------------------------------------------------------------------
+
+proc ::yencode::Encode {s} {
+ set r {}
+ binary scan $s c* d
+ foreach {c} $d {
+ set v [expr {($c + 42) % 256}]
+ if {$v == 0x00 || $v == 0x09 || $v == 0x0A
+ || $v == 0x0D || $v == 0x3D} {
+ append r "="
+ set v [expr {($v + 64) % 256}]
+ }
+ append r [format %c $v]
+ }
+ return $r
+}
+
+proc ::yencode::Decode {s} {
+ if {[string length $s] == 0} {return ""}
+ set r {}
+ set esc 0
+ binary scan $s c* d
+ foreach c $d {
+ if {$c == 61 && $esc == 0} {
+ set esc 1
+ continue
+ }
+ set v [expr {($c - 42) % 256}]
+ if {$esc} {
+ set v [expr {($v - 64) % 256}]
+ set esc 0
+ }
+ append r [format %c $v]
+ }
+ return $r
+}
+
+# -------------------------------------------------------------------------
+# C coded versions for critcl built base64c package
+# -------------------------------------------------------------------------
+
+if {[package provide critcl] != {}} {
+ namespace eval ::yencode {
+ critcl::ccode {
+ #include <string.h>
+ }
+ critcl::ccommand CEncode {dummy interp objc objv} {
+ Tcl_Obj *inputPtr, *resultPtr;
+ int len, rlen, xtra;
+ unsigned char *input, *p, *r, v;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "data");
+ return TCL_ERROR;
+ }
+
+ /* fetch the input data */
+ inputPtr = objv[1];
+ input = Tcl_GetByteArrayFromObj(inputPtr, &len);
+
+ /* calculate the length of the encoded result */
+ rlen = len;
+ for (p = input; p < input + len; p++) {
+ v = (*p + 42) % 256;
+ if (v == 0 || v == 9 || v == 0x0A || v == 0x0D || v == 0x3D)
+ rlen++;
+ }
+
+ /* allocate the output buffer */
+ resultPtr = Tcl_NewObj();
+ r = Tcl_SetByteArrayLength(resultPtr, rlen);
+
+ /* encode the input */
+ for (p = input; p < input + len; p++) {
+ v = (*p + 42) % 256;
+ if (v == 0 || v == 9 || v == 0x0A || v == 0x0D || v == 0x3D) {
+ *r++ = '=';
+ v = (v + 64) % 256;
+ }
+ *r++ = v;
+ }
+ Tcl_SetObjResult(interp, resultPtr);
+ return TCL_OK;
+ }
+
+ critcl::ccommand CDecode {dummy interp objc objv} {
+ Tcl_Obj *inputPtr, *resultPtr;
+ int len, rlen, esc;
+ unsigned char *input, *p, *r, v;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "data");
+ return TCL_ERROR;
+ }
+
+ /* fetch the input data */
+ inputPtr = objv[1];
+ input = Tcl_GetByteArrayFromObj(inputPtr, &len);
+
+ /* allocate the output buffer */
+ resultPtr = Tcl_NewObj();
+ r = Tcl_SetByteArrayLength(resultPtr, len);
+
+ /* encode the input */
+ for (p = input, esc = 0, rlen = 0; p < input + len; p++) {
+ if (*p == 61 && esc == 0) {
+ esc = 1;
+ continue;
+ }
+ v = (*p - 42) % 256;
+ if (esc) {
+ v = (v - 64) % 256;
+ esc = 0;
+ }
+ *r++ = v;
+ rlen++;
+ }
+ Tcl_SetByteArrayLength(resultPtr, rlen);
+ Tcl_SetObjResult(interp, resultPtr);
+ return TCL_OK;
+ }
+ }
+}
+
+if {[info commands ::yencode::CEncode] != {}} {
+ interp alias {} ::yencode::encode {} ::yencode::CEncode
+ interp alias {} ::yencode::decode {} ::yencode::CDecode
+} else {
+ interp alias {} ::yencode::encode {} ::yencode::Encode
+ interp alias {} ::yencode::decode {} ::yencode::Decode
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# Pop the nth element off a list. Used in options processing.
+#
+proc ::yencode::Pop {varname {nth 0}} {
+ upvar $varname args
+ set r [lindex $args $nth]
+ set args [lreplace $args $nth $nth]
+ return $r
+}
+
+# -------------------------------------------------------------------------
+
+proc ::yencode::yencode {args} {
+ array set opts {mode 0644 filename {} name {} line 128 crc32 1}
+ while {[string match -* [lindex $args 0]]} {
+ switch -glob -- [lindex $args 0] {
+ -f* { set opts(filename) [Pop args 1] }
+ -m* { set opts(mode) [Pop args 1] }
+ -n* { set opts(name) [Pop args 1] }
+ -l* { set opts(line) [Pop args 1] }
+ -c* { set opts(crc32) [Pop args 1] }
+ -- { Pop args ; break }
+ default {
+ set options [join [lsort [array names opts]] ", -"]
+ return -code error "bad option [lindex $args 0]:\
+ must be -$options"
+ }
+ }
+ Pop args
+ }
+
+ if {$opts(name) == {}} {
+ set opts(name) $opts(filename)
+ }
+ if {$opts(name) == {}} {
+ set opts(name) "data.dat"
+ }
+ if {! [string is boolean $opts(crc32)]} {
+ return -code error "bad option -crc32: argument must be true or false"
+ }
+
+ if {$opts(filename) != {}} {
+ set f [open $opts(filename) r]
+ fconfigure $f -translation binary
+ set data [read $f]
+ close $f
+ } else {
+ if {[llength $args] != 1} {
+ return -code error "wrong \# args: should be\
+ \"yencode ?options? -file name | data\""
+ }
+ set data [lindex $args 0]
+ }
+
+ set opts(size) [string length $data]
+
+ set r {}
+ append r [format "=ybegin line=%d size=%d name=%s" \
+ $opts(line) $opts(size) $opts(name)] "\n"
+
+ set ndx 0
+ while {$ndx < $opts(size)} {
+ set pln [string range $data $ndx [expr {$ndx + $opts(line) - 1}]]
+ set enc [encode $pln]
+ incr ndx [string length $pln]
+ append r $enc "\r\n"
+ }
+
+ append r [format "=yend size=%d" $ndx]
+ if {$opts(crc32)} {
+ append r " crc32=" [crc::crc32 -format %x $data]
+ }
+ return $r
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# Perform ydecoding of a file or data. A file may contain more than one
+# encoded data section so the result is a list where each element is a
+# three element list of the provided filename, the file size and the
+# data itself.
+#
+proc ::yencode::ydecode {args} {
+ array set opts {mode 0644 filename {} name default.bin}
+ while {[string match -* [lindex $args 0]]} {
+ switch -glob -- [lindex $args 0] {
+ -f* { set opts(filename) [Pop args 1] }
+ -- { Pop args ; break; }
+ default {
+ set options [join [lsort [array names opts]] ", -"]
+ return -code error "bad option [lindex $args 0]:\
+ must be -$opts"
+ }
+ }
+ Pop args
+ }
+
+ if {$opts(filename) != {}} {
+ set f [open $opts(filename) r]
+ set data [read $f]
+ close $f
+ } else {
+ if {[llength $args] != 1} {
+ return -code error "wrong \# args: should be\
+ \"ydecode ?options? -file name | data\""
+ }
+ set data [lindex $args 0]
+ }
+
+ set state false
+ set result {}
+
+ foreach {line} [split $data "\n"] {
+ set line [string trimright $line "\r\n"]
+ switch -exact -- $state {
+ false {
+ if {[string match "=ybegin*" $line]} {
+ regexp {line=(\d+)} $line -> opts(line)
+ regexp {size=(\d+)} $line -> opts(size)
+ regexp {name=(\d+)} $line -> opts(name)
+
+ if {$opts(name) == {}} {
+ set opts(name) default.bin
+ }
+
+ set state true
+ set r {}
+ }
+ }
+
+ true {
+ if {[string match "=yend*" $line]} {
+ set state false
+ lappend result [list $opts(name) $opts(size) $r]
+ } else {
+ append r [decode $line]
+ }
+ }
+ }
+ }
+
+ return $result
+}
+
+# -------------------------------------------------------------------------
+
+package provide yencode 1.1.3
+
+# -------------------------------------------------------------------------
+#
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
+
diff --git a/tcllib/modules/base64/yencode.test b/tcllib/modules/base64/yencode.test
new file mode 100644
index 0000000..9d1813b
--- /dev/null
+++ b/tcllib/modules/base64/yencode.test
@@ -0,0 +1,99 @@
+# yencode.test - Copyright (C) 2002 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# Tests for the Tcllib yencode package
+#
+# -------------------------------------------------------------------------
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# -------------------------------------------------------------------------
+# RCS: @(#) $Id: yencode.test,v 1.11 2008/12/12 04:57:46 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.2
+testsNeedTcltest 1.0
+
+testing {
+ # FUTURE: Switch tcl/critcl implementations
+ useTcllibC
+ useLocalKeep yencode.tcl yencode
+}
+
+# -------------------------------------------------------------------------
+
+if {[llength [info commands ::yencode::CEncode]]} {
+ puts "> critcl based"
+} else {
+ puts "> pure tcl"
+}
+
+proc ::yencode::loaddata {filename {translation auto}} {
+ set f [open $filename r]
+ fconfigure $f -translation $translation
+ set data [read $f]
+ close $f
+ return $data
+}
+
+# -------------------------------------------------------------------------
+
+set datafile [localPath yencode.test.data]
+
+test yencode-1.0 {yencode yEnc test file} {
+ set enc [::yencode::yencode -file $datafile]
+ set dec [::yencode::ydecode $enc]
+ set chk [::yencode::loaddata $datafile]
+ string equal $dec $chk
+} {0}
+
+
+# -------------------------------------------------------------------------
+
+foreach {n in out} {
+ 0 A {k}
+ 1 ABC {klm}
+ 2 \0\1\2 {*+,}
+ 3 "\r\n\t" {743}
+ 4 "\xd6\xe0\xe3" {=@=J=M}
+} {
+ test yencode-2.$n.a {check the pure tcl encode} {
+ list [catch {::yencode::Encode $in} r] $r
+ } [list 0 $out]
+ test yencode-2.$n.b {check the pure tcl decode} {
+ list [catch {::yencode::Decode $out} r] $r
+ } [list 0 $in]
+}
+
+if {[llength [info commands ::yencode::CEncode]]} {
+ foreach {n in out} {
+ 0 A {k}
+ 1 ABC {klm}
+ 2 \0\1\2 {*+,}
+ 3 "\r\n\t" {743}
+ 4 "\xd6\xe0\xe3" {=@=J=M}
+ } {
+ test yencode-3.$n.a {check the critcl encode} {
+ list [catch {::yencode::Encode $in} r] $r
+ } [list 0 $out]
+ test yencode-3.$n.b {check the critcl decode} {
+ list [catch {::yencode::Decode $out} r] $r
+ } [list 0 $in]
+ }
+}
+
+# -------------------------------------------------------------------------
+
+catch {
+ unset datafile
+ rename ::yencode::loaddata {}
+}
+testsuiteCleanup
+
+# Local Variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
diff --git a/tcllib/modules/base64/yencode.test.data b/tcllib/modules/base64/yencode.test.data
new file mode 100644
index 0000000..ebadc2c
--- /dev/null
+++ b/tcllib/modules/base64/yencode.test.data
Binary files differ
diff --git a/tcllib/modules/base64/yencode.test.out b/tcllib/modules/base64/yencode.test.out
new file mode 100644
index 0000000..f17da90
--- /dev/null
+++ b/tcllib/modules/base64/yencode.test.out
@@ -0,0 +1,17 @@
+From: develop@winews.net
+Newsgroups: yenc
+Date: 27 Oct 2001 15:07:44 +0200
+Subject: yEnc-Prefix: "testfile.txt" 584 yEnc bytes - yEnc test (1)
+Message-ID: <4407f.ra1200@liebchen.winews.net>
+Path: liebchen.winews.net!not-for-mail
+Lines: 16
+X-Newsreader: MyNews
+
+--
+=ybegin line=128 size=584 name=testfile.txt
+oJWJ~JR[S74k}mssdJ\__XXZ74)('&%$#"! =M =J=I=@
+~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSR
+QPONMLKJIHGFEDCBA@?>=}<;:9876543210/=n-,+*74k}mssdJZXX\__74*+,-=n/0123456789:;<=}>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkl
+mnopqrstuvwxyz{|}~
+=@=I=J =M !"#$%&'()74oJJ~74
+=yend size=584 crc32=ded29f4f