We have a vendor that can only send us a uu-encoded PDF. Is there a way to decrypt it in Ensemble?


Scott Roth

The Ohio State University Wexner Medical Center

  • 0
  • 0
  • 154
  • 0
  • 1



While there's nothing officially supported in the product, I've pulled some code from a sample that a colleague wrote years ago that should do what you need.  Please note that I have not personally tested this code, and since it is not part of the product, it has not been through any QA testing by InterSystems, so you would need to test and use at your own risk.

/// This method takes in an UUencoded GlobalCharacterStream and 
/// returns an UUdecoded GlobalBinaryStream. 
/// UUencoding is a form of binary-to-text encoding that originated in the Unix program 
/// uuencode, for encoding binary data for transmission over the uucp mail system. 
/// The name "uuencoding" is derived from "Unix-to-Unix encoding". Since uucp converted 
/// characters between various computers' character sets, uuencode was used to convert 
/// the data to fairly common characters that were unlikely to be "translated" and 
/// thereby destroy the file. This method UUDECODE reverses the effect of uuencode, 
/// recreating the original binary file exactly.
/// ref.: http://en.wikipedia.org/wiki/Uuencoding
Method UUDECODE(ByRef sUUE As %GlobalCharacterStream, Output sUUD As %GlobalBinaryStream) As %String
 S UUDFilename=""
 D sUUE.Rewind()
 S data=sUUE.ReadLine()
 // A file in uuencoded format starts with a header line of the form:
 // begin (mode) (filename)
 // where (mode) is the file's Unix read/write/execute permissions as three octal digits,
 // and (filename) is the name to be used when recreating the binary data. 
 S data=$e(data,$f(data,"begin"),$l(data))
 F {
	 Q:" 01234567"'[$e(data,1,1)
	 S $e(data,1,1)=$tr($e(data,1,1)," 01234567","") ; ignore (mode)
 S UUDFilename=data
 While('sUUE.AtEnd) {
	 S data=sUUE.ReadLine() 
	 // The file ends with two trailer lines:
	 // `
	 // end
	 // (The grave accent indicates a line that encodes zero bytes)
	 // Each data line starts with a character indicating the number of data bytes 
	 // encoded on the line and ends with a newline character. All data lines,
	 // except perhaps the last, encode 45 bytes of data. The corresponding encoded
	 // length value is 'M' (see uudec() below), so most lines begin with 'M'.
	 S n=$$uudec($e(data,1,1))
	 // Each group of four bytes will be decoded back to a 24-bit value. This
	 // 24-bit value is formed by 4 groups of 6-bit values, each corresponds
	 // to every byte in the encoded group. 
	 F i=2:4:$L(data)
		 if n>=1 {
			 ; decode(first 6-bit)<<2 | decode(second 6-bit)>>4
			 ;        first 6-bit: 00XXXXXX --> XXXXXX00
			 ;       second 6-bit: 00YYbbbb --> 000000YY 
			 ; first decoded byte: XXXXXXYY
			 S ch=$zb($zb($$uudec($e(data,i,i))*4,255,1),$$uudec($e(data,i+1,i+1))\16,7) 
			 D sUUD.Write($c(ch))
		 if n>=2 {
			 ; decode(second 6-bit)<<4 | decode(third 6-bit)>>2
			 ;        second 6-bit: 00bbXXXX --> XXXX0000
			 ;         third 6-bit: 00YYYYbb --> 0000YYYY
			 ; second decoded byte: XXXXYYYY
			 S ch=$zb($zb($$uudec($e(data,i+1,i+1))*16,255,1),$$uudec($e(data,i+2,i+2))\4,7) 
			 D sUUD.Write($c(ch))
		 if n>=3 {
			 ; decode(third 6-bit)<<6 | decode(fourth 6-bit)
			 ;        third 6-bit: 00bbbbXX --> XX000000
			 ;       fourth 6-bit:              00YYYYYY
			 ; third decoded byte: XXYYYYYY
			 S ch=$zb($zb($$uudec($e(data,i+2,i+2))*64,255,1),$$uudec($e(data,i+3,i+3)),7) 
			 D sUUD.Write($c(ch))
		 S n=n-3
 Q UUDFilename
 // Each uuencoded byte has a range of values from 0 to 63. When 32 is added, 
 // the ASCII characters will lie in the range 32 (space) to 95 (underscore).
 // ASCII characters greater than 95 may also be used, but only the six 
 // right-most bits are relevant. Since the space character is deemed 
 // problematic for data transmission, so the grave accent (` or ASCII 96) is
 // used to represent the encoded zero value. 
	Q $zb($a(ch)-32,63,1) ; 6 bits AND