#!/bin/sh # # Conjecturally Secure Pseudo-Random Document Generator # # Copyright (c) 2026 Doan Luu Duc Tai doan@luuduct.ai # SPDX-License-Identifier: 0BSD OR Apache-2.0 # # This script is dual-licensed under the Zero-Clause BSD License (0BSD) # OR the Apache License, Version 2.0 (Apache-2.0), at your option. # See the LICENSE file for the full text of both licenses. OUTPUT_FILE="document.odt" SCRIPT_DIR=$(dirname "$0") WORDLIST="$SCRIPT_DIR/words.txt" if [ ! -r "$WORDLIST" ]; then printf "Error: The required word list was not found or is not readable at:\n" >&2 printf " %s\n" "$WORDLIST" >&2 printf "Please ensure 'words.txt' is placed in the same folder as this script.\n" >&2 exit 1 fi if ! command -v zip >/dev/null 2>&1; then printf "Error: The 'zip' utility is required but was not found in PATH.\n" >&2 exit 1 fi TMP_DIR="./odt_tmp_$$" mkdir -p "$TMP_DIR" cleanup() { rm -rf "$TMP_DIR" } trap cleanup 0 INT TERM mkdir -p "$TMP_DIR/META-INF" printf "application/vnd.oasis.opendocument.text" >"$TMP_DIR/mimetype" cat <<'EOF' >"$TMP_DIR/META-INF/manifest.xml" EOF cat <<'EOF' >"$TMP_DIR/styles.xml" EOF cat <<'EOF' >"$TMP_DIR/meta.xml" POSIX Shell ODT Generator EOF cat <<'EOF' >"$TMP_DIR/settings.xml" EOF SEED=$( ( date times 2>/dev/null ls -l /tmp 2>/dev/null env 2>/dev/null ) | cksum | awk '{print $1}') case "$SEED" in "" | *[!0-9]*) SEED=123456 ;; esac awk -v seed="$SEED" -v stats_file="$TMP_DIR/stats" ' BEGIN { srand(seed); word_count = 0; pages = int(50 + rand() * 31); min_words = pages * 200; if (min_words < 10000) { min_words = 10000; } total_words = min_words + int(rand() * 5001); } /^[[:alpha:]]+$/ { if (word_count < 50000) { words[word_count] = $0; word_count++; } } END { if (word_count == 0) { print "ERROR=\"No usable words found in the system wordlist.\"" > stats_file; exit 1; } print "PAGES=" pages > stats_file; print "WORDS=" total_words > stats_file; print ""; print ""; print " "; print " "; print " "; print " "; print " "; print " "; print " "; w_per_page = int(total_words / pages); words_left = total_words; for (p = 1; p <= pages; p++) { if (p == pages) { p_words = words_left; } else { variation = int(w_per_page * 0.2); if (variation < 5) { variation = 5; } p_words = w_per_page + int(rand() * (variation * 2 + 1)) - variation; if (p_words > words_left) { p_words = words_left; } if (p_words < 10) { p_words = 10; } } words_left -= p_words; if (p > 1) { is_first_p = 1; } else { is_first_p = 0; } while (p_words > 0) { p_len = int(25 + rand() * 36); if (p_len > p_words) { p_len = p_words; } p_words -= p_len; if (is_first_p) { printf " "; is_first_p = 0; } else { printf " "; } for (w = 0; w < p_len; w++) { rnd_idx = int(rand() * word_count); word = words[rnd_idx]; if (w == 0) { word = toupper(substr(word, 1, 1)) substr(word, 2); } else { word = tolower(word); } printf "%s", word; if (w == p_len - 1) { printf("."); } else { printf(" "); } } print ""; } } print " "; print " "; print ""; } ' "$WORDLIST" >"$TMP_DIR/content.xml" if [ -f "$TMP_DIR/stats" ]; then . "$TMP_DIR/stats" fi if [ -n "$ERROR" ]; then printf "Error: %s\n" "$ERROR" >&2 exit 1 fi case "$OUTPUT_FILE" in /*) ABS_OUTPUT="$OUTPUT_FILE" ;; *) ABS_OUTPUT="$(pwd)/$OUTPUT_FILE" ;; esac rm -f "$ABS_OUTPUT" ( cd "$TMP_DIR" || exit 1 zip -X -r -n mimetype "$ABS_OUTPUT" mimetype META-INF content.xml styles.xml meta.xml settings.xml >/dev/null ) if [ $? -eq 0 ]; then printf "Document successfully created: %s\n" "$OUTPUT_FILE" printf "Generated Details:\n" printf " - Pages: %s\n" "$PAGES" printf " - Words: %s\n" "$WORDS" else printf "Error: Failed to package ODT using zip.\n" >&2 exit 1 fi