Eval [ 'From Pharo-1.1-11411 of 17 July 2010 [Latest update: #11411] on 19 February 2011 at 9:09:05 pm' ] ReadWriteStream subclass: MIMERWStream [ | readLimit | nextPut: aInt [ | res | res := super nextPut: aInt. readLimit := self readLimit max: self position. ^ res ] contents [ ^ collection copyFrom: 1 to: self readLimit. ] readLimit [ ^ readLimit ifNil: [readLimit := 0]. ] ] Object subclass: MimeConverter [ | dataStream mimeStream | dataStream [ ^dataStream ] dataStream: anObject [ dataStream := anObject ] mimeStream [ ^mimeStream ] mimeStream: anObject [ mimeStream := anObject ] mimeDecode [ "Do conversion reading from mimeStream writing to dataStream" self subclassResponsibility ] mimeEncode [ "Do conversion reading from dataStream writing to mimeStream" self subclassResponsibility ] ] MimeConverter subclass: Base64LikeConverter [ | data | FromCharTable := nil. ToCharTable := nil. Base64LikeConverter class >> initialize [ FromCharTable := Array new: 256. "nils" ToCharTable := Array new: 64. ($A asciiValue to: $Z asciiValue) doWithIndex: [:val :ind | FromCharTable at: val + 1 put: ind - 1. ToCharTable at: ind put: val asCharacter]. ($a asciiValue to: $z asciiValue) doWithIndex: [:val :ind | FromCharTable at: val + 1 put: ind + 25. ToCharTable at: ind + 26 put: val asCharacter]. ($0 asciiValue to: $9 asciiValue) doWithIndex: [:val :ind | FromCharTable at: val + 1 put: ind + 25 + 26. ToCharTable at: ind + 26 + 26 put: val asCharacter]. FromCharTable at: $+ asciiValue + 1 put: 62. ToCharTable at: 63 put: $+. FromCharTable at: $/ asciiValue + 1 put: 63. ToCharTable at: 64 put: $/ ] Base64LikeConverter class >> mimeEncode: aStream [ "Return a ReadWriteStream of characters. The data of aStream is encoded as 65 innocuous characters. (See class comment). 3 bytes in aStream goes to 4 bytes in output." | me | me := self new dataStream: aStream. me mimeStream: (MIMERWStream on: (String new: (aStream size + 20) * 4 // 3)). me mimeEncode. me mimeStream position: 0. ^me mimeStream ] mimeDecode [ "Convert a stream in base 64 with only a-z,A-Z,0-9,+,/ to a full byte stream of characters. Reutrn a whole stream for the user to read." | nibA nibB nibC nibD | [mimeStream atEnd] whileFalse: [(nibA := self nextValue) ifNil: [^dataStream]. (nibB := self nextValue) ifNil: [^dataStream]. dataStream nextPut: ((nibA bitShift: 2) + (nibB bitShift: -4)) asCharacter. nibB := nibB bitAnd: 15. (nibC := self nextValue) ifNil: [^dataStream]. dataStream nextPut: ((nibB bitShift: 4) + (nibC bitShift: -2)) asCharacter. nibC := nibC bitAnd: 3. (nibD := self nextValue) ifNil: [^dataStream]. dataStream nextPut: ((nibC bitShift: 6) + nibD) asCharacter]. ^dataStream ] mimeDecodeToByteArray [ "Convert a stream in base 64 with only a-z,A-Z,0-9,+,/ to a full ByteArray of 0-255 values. Reutrn a whole stream for the user to read." | nibA nibB nibC nibD | [mimeStream atEnd] whileFalse: [(nibA := self nextValue) ifNil: [^dataStream]. (nibB := self nextValue) ifNil: [^dataStream]. dataStream nextPut: (nibA bitShift: 2) + (nibB bitShift: -4). nibB := nibB bitAnd: 15. (nibC := self nextValue) ifNil: [^dataStream]. dataStream nextPut: (nibB bitShift: 4) + (nibC bitShift: -2). nibC := nibC bitAnd: 3. (nibD := self nextValue) ifNil: [^dataStream]. dataStream nextPut: (nibC bitShift: 6) + nibD]. ^dataStream ] mimeEncode [ "Convert from data to 6 bit characters." | phase1 phase2 raw nib lineLength | phase1 := phase2 := false. lineLength := 0. [dataStream atEnd] whileFalse: [lineLength >= 70 ifTrue: [mimeStream cr. lineLength := 0]. data := raw := dataStream next asInteger. nib := (data bitAnd: 252) bitShift: -2. mimeStream nextPut: (ToCharTable at: nib + 1). dataStream atEnd ifTrue: [raw := 0. phase1 := true] ifFalse: [raw := dataStream next]. data := ((data bitAnd: 3) bitShift: 8) + raw asInteger. nib := (data bitAnd: 1008) bitShift: -4. mimeStream nextPut: (ToCharTable at: nib + 1). dataStream atEnd ifTrue: [raw := 0. phase2 := true] ifFalse: [raw := dataStream next]. data := ((data bitAnd: 15) bitShift: 8) + raw asInteger. nib := (data bitAnd: 4032) bitShift: -6. mimeStream nextPut: (ToCharTable at: nib + 1). nib := data bitAnd: 63. mimeStream nextPut: (ToCharTable at: nib + 1). lineLength := lineLength + 4]. phase1 ifTrue: [mimeStream skip: -2; nextPut: $_; nextPut: $_. ^mimeStream]. phase2 ifTrue: [mimeStream skip: -1; nextPut: $_. ^mimeStream] ] nextValue [ "The next six bits of data char from the mimeStream, or nil. Skip all other chars" | raw num | [raw := mimeStream next. raw ifNil: [^nil]. "end of stream" raw == $= ifTrue: [^nil]. num := FromCharTable at: raw asciiValue + 1. num ifNotNil: [^num]. "else ignore space, return, tab, ..." true] whileTrue ] ] Eval [ Base64LikeConverter initialize ]