DOpus4-FromB64.rexx
/*
 *  $VER: DOpus4-FromB64 1.0 (1 Jul 2015) by Wizardry and Steamworks
 *
 *      © 2015 Wizardry and Steamworks
 *
 *  PROGRAMNAME:
 *      DOpus4-FromB64
 *
 *  FUNCTION:
 *      Decodes a file from Base64 and copies the resulting file to the other pane.
 *
 *  USAGE:
 *      ARexx command DOpus4-FromB64.rexx (from DOpus)
 *
 *  $HISTORY:
 *
 *  1 Jul 2015 : 1.0 : initial release
 *
 */
 
/*------- Configuration Variables (change these to suit your setup) --------*/
ChunkSize = 64          /* The chunk size to read: must be a multiple of 4. */
/*--------------------------------------------------------------------------*/
 
Opus = Address()    /* Get the DOpus address. */
Options RESULTS     /* Request results. */
Address value Opus  /* Use the DOpus address. */
 
Busy On             /* Set the busy pointer. */
 
Status 3                    /* Get this window. */
ThisWindow = RESULT
ThatWindow = ~ThisWindow    /* That window is not this window. */
 
/* Get this path. */
Status 13 ThisWindow
ThisPath = RESULT
If ThisPath = 'RESULT' Then
    Do
        TopText "No path in this window!"
        Busy Off
        Exit
    End
 
/* Get that path. */
Status 13 ThatWindow
ThatPath = RESULT
If ThatPath = 'RESULT' Then
    Do
        TopText "No path in that window!"
        Busy Off
        Exit
    End
 
GetSelectedAll '*' ThisWindow  /* Get all the selected items. */
Items = RESULT
If Items = 'RESULT' Then                /* If no items in this window then bail. */
    Do
        TopText "No items selected in this window!"
        Busy Off
        Exit
    End
 
/* Normalize, heh... */
Items = Translate(Translate(Items, '/', ' '), ' ', '*')
 
Count = Words(Items)    /* Get the number of selected items. */
If n <= 0 Then          /* Check if no items were selected. */
    Do                  /* If no items were selected, */
        Busy Off        /* turn off the busy pointer. */
        Exit            /* and terminate. */
    End
 
Do i = 1 To Count
    Name = Translate(Word(Items, i), ' ', '/')
    ScrollToShow Name
    NewName = Name
    Count = Length(NewName)
    If SubStr(NewName, Count-3) = '.b64' Then
        Do
            NewName = DelStr(NewName, Count-3)
        End
    If wasFileFromBase64(ThisPath||Name, ThatPath||NewName, ChunkSize, 'TopText "Reading Base64 Characters ["Count"]"') ~= 1 Then
        Do
            TopText "Failed to convert file: "Name
            Iterate i
        End
    TopText "Converted file: "Name
    Call wasDOpus4DeselectEntry(Name)
    Rescan ThatWindow
End
 
If n ~= 1 Then Rescan ThatWindow
 
TopText "<(^.-)> There you go!"
 
Busy Off    /* Turn off the busy pointer. */
Exit        /* Terminate. */
 
/*************************************************************************/
/*    Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3    */
/*************************************************************************/
wasFileFromBase64: procedure /* Decodes a file from Base64.              */
    Parse ARG Ins,Ous,Chunk,Lambda
 
    If Chunk // 4 ~= 0 Then Return 0
 
    If Open('ins', Ins, 'READ') ~= 1 | Open('ous', Ous, 'WRITE') ~= 1 Then 
        Return 0
 
    b64 =,
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
 
    Count = 0
    Do While ~Eof('ins')
        Segment = ''
        Do While Length(Segment) ~= Chunk & ~Eof('ins')
            c = ReadCh('ins', 1)
            Select
                When Pos(c, b64) = 0 Then Nop
                Otherwise Segment = Segment||c
            End
        End
        If Length(Segment) // 4 ~= 0 Then
            Do
                Close('ins')
                Close('ous')
                Return 0
            End
        Segment = wasBase64Decode(Segment)
        Length = Length(Segment)
        Interpret Lambda
        If WriteCh('ous', Segment) ~= Length Then
            Do
                Close('ins')
                Close('ous')
                Return 0
            End
        Count = Count + Length
    End
 
    Close('ins')
    Close('ous')
 
Return 1
 
/*************************************************************************/
/*    Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3    */
/*************************************************************************/
wasBase64Decode: procedure /* Decodes a Base64 string.                   */
    Parse ARG String
 
    Count = Length(String)
 
    If Count = 0 Then Return ''
 
    Pad = ''
    Select
        When SubStr(String, Count-1, 2) = '==' Then Pad = 'AA'
        When SubStr(String, Count, 1) = '=' Then Pad = 'A'
        Otherwise Nop
    End
 
    String = SubStr(String, 1, Length(String) - Length(Pad))||Pad
 
    b64 =,
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
 
    Count = Length(String)
    Result = ''
    Do i = 1 To Count By 4
        b1 = Pos(SubStr(String, i, 1), b64) - 1
        b2 = Pos(SubStr(String, i+1, 1), b64) - 1
        b3 = Pos(SubStr(String, i+2, 1), b64) - 1
        b4 = Pos(SubStr(String, i+3, 1), b64) - 1
        r1 = b1 * 4 + b2 % 16
        r2 = 16 * (b2 // 16) + (b3 % 4)
        r3 = 64 * (b3 // 4) + b4
        Result = Result||D2C(r1)||D2C(r2)||D2C(r3)
    End
 
Return SubStr(Result, 1, Length(Result) - Length(Pad))
 
/*************************************************************************/
/*    Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3    */
/*************************************************************************/
wasDOpus4DeselectEntry: procedure   /* Deselect a selected entry.        */
    Parse ARG Item
 
    GetAll '*'
    AllItems = RESULT
    AllItems = Translate(Translate(AllItems, '/', ' '), ' ', '*')
 
    n = Words(AllItems)
 
    Do i = 1 To n
        If Item = Translate(Word(AllItems, i), ' ', '/') Then
            Do
                SelectEntry i - 1 ||' '|| 0 ||' '|| 1
                Return
            End
    End
 
Return