The Trunk: Collections-topa.701.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Trunk: Collections-topa.701.mcz

commits-2
Tobias Pape uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-topa.701.mcz

==================== Summary ====================

Name: Collections-topa.701
Author: topa
Time: 10 July 2016, 9:00:58.083099 pm
UUID: 5ae1b44b-94ef-4657-a76e-387509401f08
Ancestors: Collections-eem.700

Add an Ascii85 converter akin to Base64MimeConverter

=============== Diff against Collections-eem.700 ===============

Item was added:
+ Object subclass: #Ascii85Converter
+ instanceVariableNames: 'dataStream stringStream number85 tupleSize binary'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Collections-Streams'!
+
+ !Ascii85Converter commentStamp: 'topa 7/10/2016 20:57' prior: 0!
+ I convert between binary data and an Ascii85 text representation of PostScript and PDF fame.
+ I am a little bit more efficient (~25% overhead) than Base64 (~30% overhead).
+
+ Instance Variables
+ binary: <Boolean> - Tells whether to decode to binary data or characters
+ dataStream: <PositionableStream> - The data stream to decode to or encode from (Typically does not contain Ascii85)
+ stringStream: <PositionableStream> - The text stream to decode from or encode to (Always contains Ascii85)
+ number85: <Integer> - Decoder state, accumulated read number in base85
+ tupleSize: <SmallInteger> - Number of bytes read into number85 already
+
+ 'Hello, World' ascii85Encoded.
+
+ '<~87cURD]htuF_+us~>' ascii85Decoded.
+ !

Item was added:
+ ----- Method: Ascii85Converter class>>decode:as: (in category 'convenience') -----
+ decode: aStringOrStream as: contentsClass
+
+ ^ contentsClass streamContents:
+ [:out | self decode: aStringOrStream to: out]!

Item was added:
+ ----- Method: Ascii85Converter class>>decode:to: (in category 'convenience') -----
+ decode: aStringOrStream to: outStream
+
+ ^ (self stringStream: aStringOrStream readStream dataStream: outStream)
+ decode!

Item was added:
+ ----- Method: Ascii85Converter class>>decodeToBytes: (in category 'convenience') -----
+ decodeToBytes: aStringOrStream
+ " Analogous to Base64MimeConverter>>#mimeDecodeToBytes:"
+ | expectedSize |
+ expectedSize := aStringOrStream size * 4 // 5.
+ ^ (ByteArray new: expectedSize streamContents:
+ [:stream |
+ (self stringStream: aStringOrStream readStream dataStream: stream)
+ decodeToByteArray]) readStream!

Item was added:
+ ----- Method: Ascii85Converter class>>decodeToChars: (in category 'convenience') -----
+ decodeToChars: aStringOrStream
+ " Analogous to Base64MimeConverter>>#mimeDecodeToChars:"
+ | expectedSize |
+ expectedSize := aStringOrStream size * 4 // 5.
+ ^ (String new: expectedSize streamContents:
+ [:stream | self decode: aStringOrStream to: stream]) readStream!

Item was added:
+ ----- Method: Ascii85Converter class>>encode: (in category 'convenience') -----
+ encode: aCollectionOrStream
+
+ ^ String streamContents:
+ [:out | self encode: aCollectionOrStream to: out]!

Item was added:
+ ----- Method: Ascii85Converter class>>encode:to: (in category 'convenience') -----
+ encode: aCollectionOrStream to: outStream
+
+ ^ (self stringStream: outStream dataStream: aCollectionOrStream readStream)
+ encode!

Item was added:
+ ----- Method: Ascii85Converter class>>stringStream:dataStream: (in category 'instance creation') -----
+ stringStream: aStream dataStream: anotherStream
+
+ ^ self new
+ stringStream: aStream;
+ dataStream: anotherStream;
+ yourself!

Item was added:
+ ----- Method: Ascii85Converter>>ascii (in category 'accessing') -----
+ ascii
+
+ binary := false.!

Item was added:
+ ----- Method: Ascii85Converter>>binary (in category 'accessing') -----
+ binary
+
+ binary := true.!

Item was added:
+ ----- Method: Ascii85Converter>>dataStream (in category 'accessing') -----
+ dataStream
+
+ ^dataStream!

Item was added:
+ ----- Method: Ascii85Converter>>dataStream: (in category 'accessing') -----
+ dataStream: anObject
+
+ dataStream := anObject.!

Item was added:
+ ----- Method: Ascii85Converter>>decode (in category 'conversion') -----
+ decode
+
+ self readBOD ifFalse: [^ self dataStream].
+
+ [self stringStream atEnd] whileFalse: [
+ self stringStream skipSeparators.
+ self readEOD ifTrue: [^ self endDecode]. "<--- End of data"
+
+ self decodeChar: self stringStream next ifFail: [^ self dataStream]].
+ "actually, should not reach, but our failure condition is returning the stream, anyway"
+ ^ self dataStream!

Item was added:
+ ----- Method: Ascii85Converter>>decodeChar:ifFail: (in category 'conversion') -----
+ decodeChar: char ifFail: failBlock
+
+ char = $z ifTrue: [^ self decodeZIfFail: failBlock].
+
+ (char between: $!! and: $u) ifFalse: [^ failBlock value].
+
+ self incrementTupleSize.
+ self incrementNumber85: char asInteger - 33 * (self pow85 at: self tupleSize).
+ self tupleSize = 5 ifTrue:
+ [self isBinary
+ ifTrue: [self writeBytes255: self number85 atMax: 4]
+ ifFalse: [self writeChars255: self number85 atMax: 4].
+ self resetDecoderState]!

Item was added:
+ ----- Method: Ascii85Converter>>decodeToByteArray (in category 'conversion') -----
+ decodeToByteArray
+
+ self binary.
+ ^ self decode!

Item was added:
+ ----- Method: Ascii85Converter>>decodeZIfFail: (in category 'conversion') -----
+ decodeZIfFail: failBlock
+
+ self tupleSize ~= 0 ifTrue: [^ failBlock value].
+ self dataStream next: 4 put: (self isBinary ifTrue: [0] ifFalse: [Character null]).
+ !

Item was added:
+ ----- Method: Ascii85Converter>>encode (in category 'conversion') -----
+ encode
+
+ | lineLength  |
+
+ lineLength := 0.
+ self stringStream nextPutAll: '<~'.
+ [self dataStream atEnd] whileFalse: [
+ | raw data out |
+ lineLength >= 74 ifTrue: [self stringStream cr.  lineLength := 0].
+ out := 5.
+ raw := (self dataStream next: 4) asByteArray.
+ raw size < 4 ifTrue:
+ [out := raw size + 1.
+ raw := raw, (self padOfSize: 4 - raw size)].
+ data := raw unsignedLongAt: 1 bigEndian: true.
+ data = 0
+ ifTrue: [self stringStream nextPut: $z. lineLength := lineLength + 1]
+ ifFalse: [self write85: data atMax: out. lineLength := lineLength + out]].
+ self stringStream nextPutAll: '~>'.
+ ^ self stringStream
+ !

Item was added:
+ ----- Method: Ascii85Converter>>endDecode (in category 'private') -----
+ endDecode
+
+ self tupleSize  > 0 ifTrue:
+ [self incrementNumber85: (self pow85 at: self tupleSize).
+ self isBinary
+ ifTrue: [self writeBytes255: self number85 atMax: self tupleSize - 1]
+ ifFalse: [self writeChars255: self number85 atMax: self tupleSize - 1]].
+ ^ self dataStream!

Item was added:
+ ----- Method: Ascii85Converter>>incrementNumber85: (in category 'private') -----
+ incrementNumber85: aNumber
+
+ number85 := number85 + aNumber.
+
+ !

Item was added:
+ ----- Method: Ascii85Converter>>incrementTupleSize (in category 'private') -----
+ incrementTupleSize
+
+ tupleSize := tupleSize + 1.
+ !

Item was added:
+ ----- Method: Ascii85Converter>>initialize (in category 'initialize-release') -----
+ initialize
+
+ super initialize.
+ self ascii.
+ self resetDecoderState.!

Item was added:
+ ----- Method: Ascii85Converter>>isBinary (in category 'testing') -----
+ isBinary
+
+ ^ binary!

Item was added:
+ ----- Method: Ascii85Converter>>number85 (in category 'accessing') -----
+ number85
+
+ ^ number85!

Item was added:
+ ----- Method: Ascii85Converter>>padOfSize: (in category 'private') -----
+ padOfSize: aNumber
+
+ aNumber = 1 ifTrue: [^ #(0)].
+ aNumber = 2 ifTrue: [^ #(0 0)].
+ aNumber = 3 ifTrue: [^ #(0 0 0)].
+ self error: 'Should not reach'.!

Item was added:
+ ----- Method: Ascii85Converter>>pow85 (in category 'private') -----
+ pow85
+
+ ^ #(52200625 614125 7225 85 1) "{85*85*85*85 . 85*85*85 . 85*85 . 85. 1}"!

Item was added:
+ ----- Method: Ascii85Converter>>readBOD (in category 'private') -----
+ readBOD
+
+ self stringStream skipSeparators.
+ self stringStream peek = $< ifFalse: [^ false] ifTrue:
+ [self stringStream next. "ignore"
+ self stringStream peek = $~ ifFalse: [^ false] ifTrue:
+ [self stringStream next "ignore"]].
+ ^ true!

Item was added:
+ ----- Method: Ascii85Converter>>readEOD (in category 'private') -----
+ readEOD
+
+ self stringStream skipSeparators.
+ self stringStream peek = $~ ifFalse: [^ false] ifTrue:
+ [self stringStream next. "ignore"
+ self stringStream peek = $> ifFalse: [^ false] ifTrue:
+ [self stringStream next "ignore"]].
+ ^ true!

Item was added:
+ ----- Method: Ascii85Converter>>resetDecoderState (in category 'private') -----
+ resetDecoderState
+
+ number85 := 0.
+ tupleSize := 0.
+ !

Item was added:
+ ----- Method: Ascii85Converter>>stringStream (in category 'accessing') -----
+ stringStream
+
+ ^ stringStream!

Item was added:
+ ----- Method: Ascii85Converter>>stringStream: (in category 'accessing') -----
+ stringStream: anObject
+
+ stringStream := anObject.!

Item was added:
+ ----- Method: Ascii85Converter>>tupleSize (in category 'accessing') -----
+ tupleSize
+
+ ^ tupleSize!

Item was added:
+ ----- Method: Ascii85Converter>>write85:atMax: (in category 'writing') -----
+ write85: anInteger atMax: aNumber
+
+ | c1 c2 c3 c4 c5 remain |
+ remain := anInteger.
+ c5 := (remain \\ 85 + 33) asCharacter. remain := remain // 85.
+ c4 := (remain \\ 85 + 33) asCharacter. remain := remain // 85.
+ c3 := (remain \\ 85 + 33) asCharacter. remain := remain // 85.
+ c2 := (remain \\ 85 + 33) asCharacter. remain := remain // 85.
+ c1 := (remain \\ 85 + 33) asCharacter. remain := remain // 85.
+ aNumber > 0 ifTrue: [self stringStream nextPut: c1.
+ aNumber > 1 ifTrue: [self stringStream nextPut: c2.
+ aNumber > 2 ifTrue: [self stringStream nextPut: c3.
+ aNumber > 3 ifTrue: [self stringStream nextPut: c4.
+ aNumber > 4 ifTrue: [self stringStream nextPut: c5]]]]].
+ !

Item was added:
+ ----- Method: Ascii85Converter>>writeBytes255:atMax: (in category 'writing') -----
+ writeBytes255: anInteger atMax: aNumber
+
+ (aNumber between: 1 and: 4) ifFalse: [^ self error: 'Unexpected byte count'].
+ 4 to: (5 - aNumber) by: -1 do:
+ [:index | self dataStream nextPut: (anInteger digitAt: index)].
+ !

Item was added:
+ ----- Method: Ascii85Converter>>writeChars255:atMax: (in category 'writing') -----
+ writeChars255: anInteger atMax: aNumber
+
+ (aNumber between: 1 and: 4) ifFalse: [^ self error: 'Unexpected byte count'].
+ 4 to: (5 - aNumber) by: -1 do:
+ [:index | self dataStream nextPut: (anInteger digitAt: index) asCharacter].
+ !

Item was added:
+ ----- Method: ByteArray>>ascii85Encoded (in category 'converting') -----
+ ascii85Encoded
+ "Encode the receiver as Ascii85"
+ "'Hello World' asByteArray ascii85Encoded"
+
+ ^ (Ascii85Converter encode: self readStream) contents!

Item was added:
+ ----- Method: String>>ascii85Decoded (in category 'converting') -----
+ ascii85Decoded
+ "Decode the receiver from Ascii85"
+ "'<~87cURD]i,""Ebo7~>' ascii85Decoded"
+
+ ^ self ascii85DecodedAs: self class
+ !

Item was added:
+ ----- Method: String>>ascii85DecodedAs: (in category 'converting') -----
+ ascii85DecodedAs: aClass
+ "Decode the receiver from Ascii85"
+ "'<~87cURD]i,""Ebo7~>' ascii85DecodedAs: String"
+
+ ^ Ascii85Converter decode: self as: aClass!

Item was added:
+ ----- Method: String>>ascii85Encoded (in category 'converting') -----
+ ascii85Encoded
+ "Encode the receiver as Ascii85"
+ "'Hello World' ascii85Encoded"
+
+ ^ (Ascii85Converter encode: self readStream) contents
+ !