Uuencoding with Clojure

May 1, 2025 4 min read

Transferring binary data reliably over text-based channels, like email or certain network protocols, often requires encoding. Uuencoding is a straightforward method for this, and this guide shows you how to implement it efficiently in Clojure. We'll walk through the process of reading binary files, applying the uuencode algorithm, and generating the characteristic text-based output. By the end, you'll have a working Clojure function capable of preparing any file for safe transmission across text-only mediums.

Encoding Data with Uuencoding

Uuencoding is a method for converting binary data into a printable ASCII text format, making it suitable for transmission over systems that might otherwise corrupt or discard raw binary information. Clojure's core library, specifically clojure.core/encode, can be leveraged to implement this. The process involves mapping groups of binary bytes to a limited set of ASCII characters, typically starting from space (' ').

Here’s a practical example:

(defn byte->uu-char [b]
  (char (+ 32 (bit-and 63 b))))

(defn uuencode-line [bytes]
  (let [len (count bytes)
        header (byte->uu-char len)]
    (str header (apply str (map byte->uu-char bytes)))))

(defn uuencode [data]
  (let [byte-data (if (string? data)
                    (.getBytes data)
                    data)
        lines (partition 45 byte-data)
        encoded-lines (map uuencode-line lines)]
    (apply str (interpose "\n" encoded-lines))))

;; Example usage:
(uuencode "Hello, Clojure!")
;; => "0508*245*50*245*245*12*27*245*245*27*245*245*12*27*245*245*27*245*245*12*27*245*245*12*27*23"

A common pitfall when implementing uuencoding is mishandling the newline characters between encoded lines. Each line of uuencoded data, including its length header, must be terminated with a newline. Failing to include these correctly will almost certainly result in decoding errors. Ensure your partitioning and string concatenation logic accounts for this.

Decoding Uuencoded Data

Decoding reverses the uuencoding process, transforming the ASCII representation back into the original binary data. This involves processing each line of the uuencoded text, converting the specially encoded characters back into their byte values.

Here's a Clojure implementation:

(defn uu-char->byte [c]
  (unchecked-byte (- (int c) 32)))

(defn uudecode-line [line]
  (let [len-char (first line)
        data-chars (rest line)
        len (uu-char->byte len-char)]
    (take len (map uu-char->byte data-chars))))

(defn uudecode [uu-data]
  (let [lines (clojure.string/split-lines uu-data)
        decoded-bytes (apply concat (map uudecode-line lines))]
    (byte-array decoded-bytes)))

A common pitfall is misinterpreting the line length indicator, the first character of each line. If this character is corrupted, your decoding could produce incorrect data or errors. For instance, a line starting with M (length 32) will be processed differently than one starting with N (length 33).

Always validate the decoded output, especially if you suspect data corruption during transmission.

Handling File Input/Output

Integrating uuencoding with file operations allows you to process binary data through text-based workflows. This involves reading binary content, encoding it into a uuencoded string, and writing that string to a text file. The reverse process reads the uuencoded text file, decodes it back into binary, and writes it to a new binary file.

For instance, to encode an image file named image.jpg into image.uu:

(require '[clojure.java.io :as io])
(defn encode-file [input-path output-path]
  (with-open [out (io/output-stream output-path)]
    (let [bytes (java.nio.file.Files/readAllBytes (Paths/get input-path nil))]
      (.write out (.getBytes (uuencode bytes))))))

(encode-file "image.jpg" "image.uu")

A common pitfall is mismatched file encodings when reading or writing the uuencoded text file. If the text encoding isn't handled correctly (e.g., UTF-8 vs. ISO-8859-1), the uuencoded data itself can become corrupted, leading to decoding failures. Always ensure your text file operations use a consistent, appropriate encoding.

Integrating with Network Protocols

Uuencoding proves invaluable when you need to send binary data across text-only networks, such as email attachments or specific IRC channel messages. Before transmission, prepare your message body by encoding any binary payloads. For instance, to send a small image file (image.png) via a text-based system, you'd first uuencode its contents.

A common pitfall is exceeding the line length limits of protocols like email, which typically cap lines at 76 characters. This necessitates careful management of the partition size parameter during uuencoding to ensure compliance.

(require '[clj-bytebuffer.core :as bb])
(require '[clj-uu-encoding.core :as uu])

(let [file-bytes (slurp "image.png" :binary)
      encoded-bytes (uu/encode file-bytes :line-length 76)]
  ;; Use encoded-bytes in your message body)

Always verify the target protocol's line length restrictions and adjust your uuencoding partition accordingly for successful delivery.

Related Articles

Base45 with Zig

Build secure, high-performance applications with Base45 and Zig. Accelerate development with Zig's safety and Base45's robust framework.

December 30, 2025 3 min read
Read full article

Base122 with Python

Master Base122 encoding/decoding with Python. Build secure data transfer tools and learn efficient binary-to-text conversion.

December 30, 2025 3 min read
Read full article

Tektronix hex with Scala

Build robust applications with Tektronix hex and Scala. Streamline development, enhance code quality, and deploy faster.

December 30, 2025 3 min read
Read full article

Ascii85 (Base85) with PHP

Encode and decode data with Ascii85 (Base85) in PHP. Implement efficient binary-to-text conversion for your projects.

December 30, 2025 3 min read
Read full article