Converting ASCII85 to Binary

Is there a function or procedure in clarion to convert a txt file containing information encoded in ASCII85 to binary

Thanks in advance

Hi,

I’m not sure there is one built in, but 3rd party products support this function.
Our Chilkat wrapper for the Chilkat library includes that functionality - it can be accomplished in 2 or 3 lines of code - so nice and simple :slight_smile:

Happy to demonstrate it to you if you like - feel free to pop in on our Monday webinar and I’ll knock up an example using your file.

Regards,

Andy
www.noyantis.com

Hi Francisco

it looks like you have a 3rd party option with Andy’s Noyantis wrapper for Chilkat library, but if you need to write it yourself, have a look at

as it looks quite straightforward to code. So, assuming you are a programmer then give it a go and if you get stuck then yell out as many people here can no doubt help.

cheers

Geoff R

Hi there, thanks for your answers, ill check 3rd party product Andy. And absolutely ill give it a try to my brain to writing myself :sweat_smile:

How did you go Francisco?

While I thought you would learn more doing it yourself rather than seeing someone else’s code, I did feel that perhaps I could have been more helpful.

So I have spent a couple of hours and written both Encode and Decode functions for ASCII85.

I always use StringTheory for all handling of strings and hence have done so here, but the code should be easy to adapt if you use the inbuilt SystemStringClass or something else.

so to encode a text file to ASCII85

st stringTheory

 CODE
  if ~st.loadFile('whatever.txt')
    Message('Failed to load file whatever.txt||Error: '& st.LastError)
    ! error handling
  end    
  Ascii85Encode(st)
  st.SaveFile('whatever.A85')

and similarly to decode an Ascii85 encoded file:

  st.loadFile('whatever.A85')
  Ascii85Decode(st)
  st.SaveFile('whatever.txt')

I’ve kept it simple and the two functions take a ST object and then either encode or decode it.

StringTheory has lots of builtin encoding methods (eg for Base64 and various unicodes etc) but doesn’t currently (vers 3.37) have ones for Ascii85 so I will send these to Bruce at Capesoft in case he wants to include them in a future version.

Note that there are a few variations of Ascii85 so you may have to tweak this code if your files are using a different variation. But I have allowed for the short form of zeroes (low-values) and spaces which are represented by ‘z’ and ‘y’ respectively as a form of compression.

The two functions are quite compact and seem quite fast on my testing. Any questions or problems yell out and any problems provide a sample file that is failing (input and expected output) and I will have a look when I get a chance. Obviously this code is provided “AS IS” so do your own testing!

Ascii85Encode        PROCEDURE  (StringTheory pSt)
st       StringTheory
myLong   long,auto
myStr    String(4),over(myLong)
tempStr  String(4),auto        
x        long,auto
y        long,auto
padChars long,auto
out5     String(5),auto

  CODE

  if ~pSt._DataEnd then return.
  padChars = pSt._DataEnd % 4
  if padChars then padChars = 4 - padChars; pSt.append(all('<0>',padChars)).   ! pad with null chars
  st.SetLength(pSt._DataEnd * 5 / 4)        ! preallocate output memory
  st.free()
  loop x = 1 to pSt._DataEnd by 4
    ! swap endian-ness as we go...
    myStr[1] = pSt.valueptr[x+3]
    myStr[2] = pSt.valueptr[x+2]
    myStr[3] = pSt.valueptr[x+1]
    myStr[4] = pSt.valueptr[x]
    if ~myLong then st.append('z'); cycle.  ! short form for 0 (low-values)
    if ~myStr  then st.append('y'); cycle.  ! short form for spaces 
    loop y = 1 to 4
      out5[6-y] = chr(int(myLong%85) + 33)
      mylong /= 85
    end
    out5[1] = chr(myLong + 33)
    st.append(out5)
  end
  if padChars then st.setLength(st._DataEnd - padChars).
  pSt._StealValue(st)    ! point our passed object to our output


Ascii85Decode        PROCEDURE  (StringTheory pSt)
st       StringTheory
myLong   long
myStr    String(4),over(myLong)
x        long,auto
y        long
padChars long,auto

  CODE
  if pSt._DataEnd > 3 and pSt.startsWith('<<~') and pSt.endsWith('~>') 
    pSt.crop(3, pSt._DataEnd-2)  ! remove Adobe begin/end chars
  end
  padChars = pSt._DataEnd % 5
  if padChars then padChars = 5 - padChars; pSt.append(all('u',padChars)).   ! pad with u chars
 
  loop x = 1 to pSt._DataEnd
    case val(pSt.valueptr[x])
    of 122; st.append('<0,0,0,0>')      !z used for zeroes (low-values)
    of 121; st.append('<32,32,32,32>')  !y used for spaces
    of 33 to 117
      y += 1
      myLong = (myLong * 85) + val(pSt.valueptr[x]) - 33 
      if y = 5
        st.append(myStr[4])
        st.append(myStr[3])
        st.append(myStr[2])
        st.append(myStr[1])
        y = 0
        myLong = 0
      end
    end !case
  end 
  if padChars then st.setLength(st._DataEnd - padChars).
  pSt._StealValue(st)    ! point our passed object to our output
3 Likes

That’s impressively small Geoff!

Jeff Atwood is one of the main guys behind this Discourse software and Coding Horror. He had a C# class that looked good to me, so I converted that to Clarion last night. It handles Whitespace, the Prefix / Suffix, line breaking on output. It did not support the ‘y’ for spaces, but that’s not part of the Adobe Ascii85 standard. Would be easy to add, but needs to be optional.

I know it converts the Wikipedia ASCII 85 example:

Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.

<~9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>[email protected]$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,
O<DJ+*.@<*K0@<6L(Df-\0Ec5e;DffZ(EZee.Bl.9pF"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKY
i(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIa
l(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G
>uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c~>
3 Likes

Thanks Carl! It is amazing that there previously wasn’t a Clarion language implementation of ASCII85 and now there are two the same day!

And it is interesting to compare the different approaches.

I have had some private discussions with Carl, who pointed out that my “myLong” was dangerous where the top bit could have been on and so should have been “myUlong”. Anyway I have changed the code to use a ULONG where necessary and a LONG where possible as LONG’s are faster for arithmatic without possible intermediate conversion to Decimal or Real.

Carl also mentioned that the space compression using ‘y’ was not supported by Adobe so I have added a parameter for Adobe (which defaults to true). The space compression (where four spaces goes to a single character ‘y’ rather than 5 characters) is off if Adobe encoding is requested - Adobe also wraps the encoded string in <~ and ~>.

I have added line wrapping as an option and defaulted it to 75.

The padding on the decoding has also changed a bit as I realized that it couldn’t be done so early when we didn’t know how many line feeds or other excluded characters there were. Sure we could have done something like pSt.KeepChars() with a list of OK characters but that would have meant traversing the string twice - once in KeepChars and once in our code so I decided against that.

Talking of such things I was a bit lazy with the line wrapping in the encode. I used st.SplitEvery() as it is just too easy to do that then re-join with the line breaks (being careful as Carl also advised not to split a line amidst the final ~> in Adobe mode). This does roughly double the output memory requirement as it briefly has the string split up in the lines queue. I may later revisit that and put in the line breaks as it goes along but this will certainly do for the moment - believe me splitting and joining in ST are incredibly fast.

anyway enough for now - updated code follows

cheers

Geoff R

Ascii85Encode        PROCEDURE  (StringTheory pSt,Long pWrapLen=75,Bool pAdobe=1)
st       StringTheory
myLong   long,auto
myULong  ulong,over(myLong)
myStr    String(4),over(myLong)
tempStr  String(4),auto        
x        long,auto
y        long,auto
padChars long,auto
outLen   long,auto
out5     String(5),auto

  CODE
  if ~pSt._DataEnd then return.
  if pWrapLen < 0  then pWrapLen = 0.

  padChars = pSt._DataEnd % 4
  if padChars then padChars = 4 - padChars; pSt.append(all('<0>',padChars)).   ! pad with null chars
  outLen = (pSt._DataEnd * 5 / 4) + choose(~pAdobe,0,4)   ! adobe has 4 extra chars
  if pWraplen then outlen += 2 * int(outlen / pWrapLen).  ! add 2 chars for each line break  
  st.SetLength(outlen)  ! preallocate output memory (optional)
  if pAdobe 
    st.setValue('<<~')
  else
    st.free()
  end
  loop x = 1 to pSt._DataEnd by 4
    ! swap endian-ness as we go...
    myStr[1] = pSt.valueptr[x+3]
    myStr[2] = pSt.valueptr[x+2]
    myStr[3] = pSt.valueptr[x+1]
    myStr[4] = pSt.valueptr[x]
    if ~myLong then st.append('z'); cycle.  ! short form for 0 (low-values)
    if ~pAdobe and ~myStr then st.append('y'); cycle. ! short form for spaces - not supported by Adobe
    out5[5] = chr(myULong%85 + 33)          ! use Ulong first time in case top bit is on
    myUlong /= 85
    loop y = 4 to 2 by -1
      out5[y] = chr(myLong%85 + 33)         ! use long where possible as faster
      mylong /= 85
    end
    out5[1] = chr(myLong + 33)
    st.append(out5)
  end
  if padChars then st.setLength(st._DataEnd - padChars).
  if pAdobe   then st.append('~>').
  if pWrapLen
    st.splitEvery(pWrapLen)
    if pAdobe and len(st.getLine(st.records())) = 1
      ! do NOT split ending ~>
      st.deleteLine(st.records()) 
      st.setLine(st.records(),st.getLine(st.records())&'>')
    end
    st.join('<13,10>')
  end
  pSt._StealValue(st)    ! point our passed object to our output


Ascii85Decode        PROCEDURE  (StringTheory pSt)
st       StringTheory
myLong   long
myUlong  ulong,over(myLong)
myStr    String(4),over(myLong)
x        long
y        long
padChars long

  CODE
  if pSt._DataEnd > 3 and pSt.startsWith('<<~') and pSt.endsWith('~>') 
    pSt.crop(3, pSt._DataEnd-2)  ! remove Adobe begin/end chars
  end
  x = 1
  loop 5 times
    loop x = x to pSt._DataEnd
      case val(pSt.valueptr[x])
      of 122; st.append('<0,0,0,0>')      !z used for zeroes (low-values)
      of 121; st.append('<32,32,32,32>')  !y used for spaces
      of 33 to 117
        y += 1
        if y < 5
          myLong = (myLong * 85) + val(pSt.valueptr[x]) - 33
        else
          myUlong = (myUlong * 85) + val(pSt.valueptr[x]) - 33 
          st.append(myStr[4])
          st.append(myStr[3])
          st.append(myStr[2])
          st.append(myStr[1])
          y = 0
          myLong = 0
        end
      end !case
    end
    if y ! padding required? 
      padChars += 1
      pSt.append('u')   ! pad with u char
    else
      break
    end
  end
  if padChars then st.setLength(st._DataEnd - padChars).
  pSt._StealValue(st)    ! point our passed object to our output
3 Likes

I also had a LONG problem with High ASCII in Decode I fixed. In this calculation _Tuple is a ULONG but the right-side was being calculated as a LONG and going negative.

SELF._tuple += (cb - _asciiOffset) * Pow85[count]

Changing to Pow85 from LONG to ULONG is one fix.

1 Like

I have been reading and understanding code and behavior of Adobe decoding. And I know about StringTheory but I am not currently using it, so I implemented Charles’s solution, it has left me very close to the goal, I will try to see what is the problem that happens to me when I decode Adobe Ascii85 string since it does not finish closing the file that is supposed to be a .zip and it appears to be incomplete or corrupted.
But it has been very useful. If i found the reason ill share it, and again thanks a lot. Even having code translation from C++ this code blows my brain out

I found the problem, originally Charles code calculate size as follows
DecodedSize = Len_s85 / 5 * 4 + 5
The size of DecodedStr was not enough (thats why didnt complete binary file and stays corrupt),
i’ve replace it with
DecodedSize = LEN (SUB (CLIP (s85), S1, S2))
this worked for the first test. but i think that formula is for a reason… maybe is missing
parenthesis priority?

The problem was ASCII 85 compresses <0,0,0,0> as a 1 ‘z’ and not 5 letters. I uploaded the corrected the calculation. I had made a few more improvements over the past few days.

DecodedSize = (Len_s85 - Zeros) / 5 * 4 + Zeros * 4 + 5

2 Likes

Hello again Francisco

glad you have got a solution - and also learnt a bit studying the code. While you didn’t opt to use StringTheory this time round I strongly recommend ST to anyone who will listen :grinning: It can save you a lot of time! (Disclaimer: I am probably a bit biased as while ST is a Capesoft product I have spent a lot of time working on it over the last decade or so.)

anyway I have had some further discussions with Carl and I have made a few changes and optimisations to my code (and Carl has made some to his code too).

the changes made to encode didn’t really result in any significant speed up, but those on decode did make it a bit faster. The encode time is generally much greater than decode.

I also have added a return code on the decode function. Previously it just ignored any errors but now I am detecting invalid ASCII85 files and return the position of the first character in error. Note that there is no such thing as an invalid file when doing an encode - it will encode anything, but on decode you can have unexpected characters if the file is corrupted.

I have chosen to leave the input unchanged when the decoding finds an error.

I guess there were three choices:

  1. clear the buffer
  2. return what had been decoded “so far” prior to error
  3. leave the buffer unaltered.

I opted for #3 although you could mount an argument for any of them.

anyway where previously we simply had:

  st.loadFile('whatever.A85')
  Ascii85Decode(st)
  st.SaveFile('whatever.txt')

you should now check for errors - a return value of 0 means all good - no errors detected.

failed long
 code
  st.loadFile('whatever.A85')
  failed = Ascii85Decode(st)
  if failed
    message('ASCII85 decode failed at byte ' & retval & ' of ' & st._DataEnd)
    ! error handling
  else
    ! all good - decoded without any problems
  end

anyway my latest versions follow:

Ascii85Encode        PROCEDURE  (StringTheory pSt,Long pWrapLen=75,Bool pAdobe=1)
st       StringTheory
myLong   long,auto
myULong  ulong,over(myLong)
myGrp    group,pre(),over(myLong)
myStr1     string(1)
myStr2     string(1)
myStr3     string(1)
myStr4     string(1)
         end ! group
x        long,auto
y        long,auto
padChars long,auto
outLen   long,auto
outstr   String(5),auto
         group,pre(),over(outStr)
out1       byte
out2       byte
out3       byte
out4       byte
out5       byte
         end ! group
  CODE
  if ~pSt._DataEnd then return.
  if pWrapLen < 0  then pWrapLen = 0.

  padChars = pSt._DataEnd % 4
  if padChars then padChars = 4 - padChars; pSt.append(all('<0>',padChars)).   ! pad with null chars
  outLen = (pSt._DataEnd * 5 / 4) + choose(~pAdobe,0,4)   ! adobe has 4 extra chars
  if pWraplen then outlen += 2 * int(outlen / pWrapLen).  ! add 2 chars for each line break  
  st.SetLength(outlen)  ! optional: preallocate output memory
  if pAdobe 
    st.setValue('<<~')
  else
    st.free()
  end
  loop x = 1 to pSt._DataEnd by 4
    ! swap endian-ness as we go...
    myStr1 = pSt.valueptr[x+3]
    myStr2 = pSt.valueptr[x+2]
    myStr3 = pSt.valueptr[x+1]
    myStr4 = pSt.valueptr[x]
    if ~myLong then st.append('z'); cycle.            ! short form for 0 (low-values)
    if ~pAdobe and myLong=20202020h then st.append('y'); cycle. ! short form for spaces - not supported by Adobe
    out5 = myULong%85 + 33   ! use Ulong first time in case top bit is on
    myUlong /= 85
    ! unrolled the loop - we use long from here as faster than ulong
    out4 = myLong%85 + 33
    mylong /= 85
    out3 = myLong%85 + 33
    mylong /= 85
    out2 = myLong%85 + 33
    mylong /= 85
    out1 = myLong%85 + 33
    st.append(outStr)
  end
  if padChars then st.setLength(st._DataEnd - padChars).
  if pAdobe   then st.append('~>').
  if pWrapLen
    st.splitEvery(pWrapLen)
    if pAdobe and len(st.getLine(st.records())) = 1
      ! do NOT split ending ~>
      st.deleteLine(st.records()) 
      st.setLine(st.records(),st.getLine(st.records())&'>')
    end
    st.join('<13,10>')
  end
  pSt._StealValue(st)    ! point our passed object to our output


Ascii85Decode        PROCEDURE  (StringTheory pSt) !,long  
st        StringTheory
myLong    long
myUlong   ulong,over(myLong)
myStr     String(4),over(myLong)
          group,pre(),over(myLong)
myStr1      string(1)
myStr2      string(1)
myStr3      string(1)
myStr4      string(1)
          end ! group
CurValue  long,auto   ! value of current character
swapStr   string(1)
x         long
y         long
padChars  long
AdobePrfx long

  CODE
  if pSt._DataEnd > 3 and pSt.startsWith('<<~') and pSt.endsWith('~>') 
    AdobePrfx = 2
    pSt.crop(3, pSt._DataEnd-2)  ! remove Adobe begin/end chars
  end
  st.setLength(pSt._DataEnd); free(st)  ! preallocate some space (optional)
  x = 1
  loop !5 times
    loop x = x to pSt._DataEnd
      curValue = val(pSt.valueptr[x])
      case curValue
      of 33 to 117
        y += 1
        if y < 5
          myLong = myLong*85 + curValue - 33
        else
          myUlong = myUlong*85 + curValue - 33
          ! swap endian-ness (reverse byte order)
          swapStr = myStr1; myStr1  = myStr4; myStr4  = swapStr  ! swap chars
          swapStr = myStr2; myStr2  = myStr3; myStr3  = swapStr  ! swap chars
          st.append(myStr)
          y = 0
          myLong = 0
        end
      of 122 
        if y then return x+AdobePrfx.  ! error - 'z' within group of 5 chars
        st.append('<0,0,0,0>')         ! z used for zeroes (low-values)
      of 121
        if y then return x+AdobePrfx.  ! error - 'y' within group of 5 chars
        st.append('<32,32,32,32>')     ! y used for spaces
      of 8 to 13 
      orof 32
        ! valid formating character so just ignore it
      else
        ! error - dud/unexpected character so return position
        return x + AdobePrfx
      end !case
    end
    if y ! padding required? 
      padChars += 1
      pSt.append('u')   ! pad with u char
    else
      break
    end
  end
  if padChars then st.setLength(st._DataEnd - padChars).
  pSt._StealValue(st)    ! point our passed object to our output
  return 0               ! all is well in the world (valid input decoded without error)

cheers for now

Geoff R

2 Likes

In my Post 6 GubHub Repo I have ST_85est.clw that has Geoff’s code and an example of using it. I updated it with his most recent post. You will need StringTheory.

I’m trying ASCII 85 to obfuscate a text file I write to disk that I would prefer not be read, but does not really need encryption. The file had a lot of spaces so with the “y” = 4 spaces it actually got smaller. My class allows specifying the Prefix / Suffix strings to be different than the Adobe <~ ~>. I used Curly Braces {xxx{ and }xxx} that are not used by the encoding so I’m sure it’s my file and I’m not jumping into the middle.

This Code Project suggests using ASCII 85 to obfuscate text placed on the clipboard. It was interesting he also used the Jeff Atwood ASCII 85 code

https://www.codeproject.com/Articles/462726/Clipboard-Codec

2 Likes

Spurred on by Carl’s efforts, I have done some more optimising on the decode function - basically previously I was following the instructions in Wikipedia where you added padding if necessary and later removed some of the characters. This seemed unnecessary so I have managed to remove some of it… and done a few other speed ups as well.

Carl mentioned to me that his latest changes to his ASCII85 decode had made it 10x faster which is amazing - my changes here yielded much smaller benefits and I think I am getting well in the area of diminishing returns so perhaps this will be my final version for now…

For completeness I am including both my ASCII85 encode and decodes, but only the decode has been further optimised.

Ascii85Encode        PROCEDURE  (StringTheory pSt,Long pWrapLen=75,Bool pAdobe=1)
st       StringTheory
myLong   long,auto
myULong  ulong,over(myLong)
         group,pre(),over(myLong)
myStr1     string(1)
myStr2     string(1)
myStr3     string(1)
myStr4     string(1)
         end ! group
x        long,auto
y        long,auto
padChars long,auto
outLen   long,auto
outstr   String(5),auto
         group,pre(),over(outStr)
out1       byte
out2       byte
out3       byte
out4       byte
out5       byte
         end ! group

  CODE
  if ~pSt._DataEnd then return.
  if pWrapLen < 0  then pWrapLen = 0.

  padChars = pSt._DataEnd % 4
  if padChars then padChars = 4 - padChars; pSt.append(all('<0>',padChars)).   ! pad with null chars
  outLen = (pSt._DataEnd * 5 / 4) + choose(~pAdobe,0,4)   ! adobe has 4 extra chars
  if pWraplen then outlen += 2 * int(outlen / pWrapLen).  ! add 2 chars for each line break  
  st.SetLength(outlen)  ! optional: preallocate output memory
  if pAdobe 
    st.setValue('<<~')
  else
    st.free()
  end
  loop x = 1 to pSt._DataEnd by 4
    ! swap endian-ness as we go...
    myStr1 = pSt.valueptr[x+3]
    myStr2 = pSt.valueptr[x+2]
    myStr3 = pSt.valueptr[x+1]
    myStr4 = pSt.valueptr[x]
    if ~myLong then st.append('z'); cycle.            ! short form for 0 (low-values)
    if ~pAdobe and myLong=20202020h then st.append('y'); cycle. ! short form for spaces - not supported by Adobe
    out5 = myULong%85 + 33   ! use Ulong first time in case top bit is on
    myUlong /= 85
    ! unrolled the loop - we use long from here as faster than ulong
    out4 = myLong%85 + 33
    mylong /= 85
    out3 = myLong%85 + 33
    mylong /= 85
    out2 = myLong%85 + 33
    mylong /= 85
    out1 = myLong%85 + 33
    st.append(outStr)
  end
  if padChars then st.setLength(st._DataEnd - padChars).
  if pAdobe   then st.append('~>').
  if pWrapLen
    st.splitEvery(pWrapLen)
    if pAdobe and len(st.getLine(st.records())) = 1
      ! do NOT split ending ~>
      st.deleteLine(st.records()) 
      st.setLine(st.records(),st.getLine(st.records())&'>')
    end
    st.join('<13,10>')
  end
  pSt._StealValue(st)    ! point our passed object to our output


Ascii85Decode        PROCEDURE  (StringTheory pSt) !,long  ! Declare Procedure
st        StringTheory
myGroup   group,pre()
myStr1      string(1)
myStr2      string(1)
myStr3      string(1)
myStr4      string(1)
myStr5      string(1)
myStr6      string(1)
myStr7      string(1)
          end ! group
myLong    long, over(myGroup)
myUlong   ulong,over(myGroup)
CurValue  long,auto   ! value of current character
x         long,auto
y         long
AdobePrfx long

  CODE
  if pSt._DataEnd > 3 and pSt.valuePtr[1 : 2] = '<<~' and pSt.valuePtr[pSt._dataEnd-1 : pSt._dataEnd] = '~>' 
    AdobePrfx = 2
    pSt.setLength(pSt._dataEnd - 2)
    x = 3
  else
    x = 1
  end
  st.setLength(pSt._DataEnd); free(st)  ! preallocate some space (optional)
  myLong = 0
  loop x = x to pSt._DataEnd
    curValue = val(pSt.valueptr[x])
    case curValue
    of 33 to 117
      y += 1
      if y < 5
        myLong = myLong*85 + curValue - 33
      else
        myUlong = myUlong*85 + curValue - 33
        myStr5 = myStr3;  myStr6 = myStr2; myStr7 = myStr1 ! swap endian-ness (reverse byte order)
        st.CatAddr(address(myStr4),4)
        y = 0
        myLong = 0
      end
    of 122 
      if y then return x+AdobePrfx.  ! error - 'z' within group of 5 chars
      st.append('<0,0,0,0>')         ! z used for zeroes (low-values)
    of 121
      if y then return x+AdobePrfx.  ! error - 'y' within group of 5 chars
      st.append('<32,32,32,32>')     ! y used for spaces
    of 8 to 13 
    orof 32
      ! valid formating character so just ignore it
    else
      ! error - dud/unexpected character so return position
      return x + AdobePrfx
    end !case
  end
  if y > 1 ! padding required?
    loop 4-y times    
      myLong = myLong*85 + 84  ! 84 = val('u') - 33 = 117 - 33
    end
    myUlong = myUlong*85 + 84
    case y
    of 2
      st.append(myStr4)
    of 3  ! myStr4 & myStr3
      myStr5 = myStr3
      st.CatAddr(address(myStr4),2)
    of 4  ! myStr4 & myStr3 & myStr2
      myStr5 = myStr3;  myStr6 = myStr2
      st.CatAddr(address(myStr4),3)
    end
  end
  pSt._StealValue(st)    ! point our passed object to our output
  return 0               ! all is well in the world (valid input decoded without error)
1 Like

Hi Carl -

Just FYI - the latest Ascii85.cwproj uploaded does not compile with C10; .compiles okay with C11.

Regards,
-Rex

I added COMPILE / OMIT _C110_ to make the Ascii85 and FileTo85 examples work under C10. The class had no issues.

The C11 System String class added method .GetStringRef(),*STRING. if you are using that class in C10 I would add that same method to save pushing a giant string on the string stack:

SystemStringClass.GetStringRef            PROCEDURE()
 CODE
    RETURN SELF.s

Thanks Rex for the heads up!

1 Like

just in case anyone is looking for this who has StringTheory, as of version 3.45 this is now included:

Version 3.45 - 11 April 2022

1 Like