/src/mahonia/writer.go

https://code.google.com/p/landproxy/ · Go · 110 lines · 80 code · 25 blank · 5 comment · 21 complexity · 7cc14955520eb874f4e87b4880091dcf MD5 · raw file

  1. package mahonia
  2. import (
  3. "io"
  4. //"unicode/utf8"
  5. "utf8"
  6. "os"
  7. )
  8. // Writer implements character-set encoding for an io.Writer object.
  9. type Writer struct {
  10. wr io.Writer
  11. encode Encoder
  12. inbuf []byte
  13. outbuf []byte
  14. }
  15. // NewWriter creates a new Writer that uses the receiver to encode text.
  16. func (e Encoder) NewWriter(wr io.Writer) *Writer {
  17. w := new(Writer)
  18. w.wr = wr
  19. w.encode = e
  20. return w
  21. }
  22. // Write encodes and writes the data from p.
  23. func (w *Writer) Write(p []byte) (n int, err os.Error) {
  24. n = len(p)
  25. if len(w.inbuf) > 0 {
  26. w.inbuf = append(w.inbuf, p...)
  27. p = w.inbuf
  28. }
  29. if len(w.outbuf) < len(p) {
  30. w.outbuf = make([]byte, len(p)+10)
  31. }
  32. outpos := 0
  33. for len(p) > 0 {
  34. int, size := utf8.DecodeRune(p)
  35. if int == 0xfffd && !utf8.FullRune(p) {
  36. break
  37. }
  38. p = p[size:]
  39. retry:
  40. size, status := w.encode(w.outbuf[outpos:], int)
  41. if status == NO_ROOM {
  42. newDest := make([]byte, len(w.outbuf)*2)
  43. copy(newDest, w.outbuf)
  44. w.outbuf = newDest
  45. goto retry
  46. }
  47. if status == STATE_ONLY {
  48. outpos += size
  49. goto retry
  50. }
  51. outpos += size
  52. }
  53. w.inbuf = w.inbuf[:0]
  54. if len(p) > 0 {
  55. w.inbuf = append(w.inbuf, p...)
  56. }
  57. n1, err := w.wr.Write(w.outbuf[0:outpos])
  58. if err != nil && n1 < n {
  59. n = n1
  60. }
  61. return
  62. }
  63. func (w *Writer) WriteRune(c int) (size int, err os.Error) {
  64. if len(w.inbuf) > 0 {
  65. // There are leftover bytes, a partial UTF-8 sequence.
  66. w.inbuf = w.inbuf[:0]
  67. w.WriteRune(0xfffd)
  68. }
  69. if w.outbuf == nil {
  70. w.outbuf = make([]byte, 16)
  71. }
  72. outpos := 0
  73. retry:
  74. size, status := w.encode(w.outbuf[outpos:], c)
  75. if status == NO_ROOM {
  76. w.outbuf = make([]byte, len(w.outbuf)*2)
  77. goto retry
  78. }
  79. if status == STATE_ONLY {
  80. outpos += size
  81. goto retry
  82. }
  83. outpos += size
  84. return w.wr.Write(w.outbuf[0:outpos])
  85. }