bytevectors.scm 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. ;;; guile-webutils -- Web application utilities for Guile
  2. ;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
  3. ;;;
  4. ;;; This program is free software: you can redistribute it and/or
  5. ;;; modify it under the terms of the GNU General Public License
  6. ;;; as published by the Free Software Foundation, either version 3 of
  7. ;;; the License, or (at your option) any later version.
  8. ;;;
  9. ;;; This program is distributed in the hope that it will be useful,
  10. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU General Public License
  15. ;;; along with this program. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. (define-module (webutils bytevectors)
  18. #:use-module (ice-9 iconv)
  19. #:use-module (rnrs io ports)
  20. #:use-module ((ice-9 binary-ports) #:select (unget-bytevector))
  21. #:use-module (rnrs bytevectors)
  22. #:export (bytevector-drop
  23. bytevector-drop-right
  24. bytevector-last
  25. bytevector-partition))
  26. (define empty-bv
  27. (make-bytevector 0))
  28. (define (bytevector-drop bv n)
  29. "Drop the first N bytes of the bytevector BV."
  30. (let ((len (bytevector-length bv)))
  31. (if (>= n len)
  32. empty-bv
  33. (let* ((new-length (- len n))
  34. (target (make-bytevector new-length)))
  35. (bytevector-copy! bv n target 0 new-length)
  36. target))))
  37. (define (bytevector-drop-right bv n)
  38. "Drop the last N bytes of the bytevector BV."
  39. (let ((len (bytevector-length bv)))
  40. (if (>= n len)
  41. empty-bv
  42. (let* ((new-length (- len n))
  43. (target (make-bytevector new-length)))
  44. (bytevector-copy! bv 0 target 0 new-length)
  45. target))))
  46. (define (bytevector-last bv)
  47. "Return the last byte of the bytevector BV."
  48. (bytevector-u8-ref bv (- (bytevector-length bv) 1)))
  49. (define (bytevector-partition separator bv)
  50. "Find the bytevector SEPARATOR in the bytevector BV and return a
  51. list of three values: the prefix, the separator, and the suffix. If
  52. there is no match the list will only contain the prefix and return #f
  53. for the remaining values."
  54. (define bv-length (bytevector-length bv))
  55. (define separator-length (bytevector-length separator))
  56. (define separator-first (bytevector-u8-ref separator 0))
  57. (define (at-separator? pos)
  58. (let ((end (+ pos (- separator-length 1))))
  59. (if (< end bv-length)
  60. (let loop ((i 0))
  61. (let ((offset (+ pos i)))
  62. (if (eqv? (bytevector-u8-ref bv offset)
  63. (bytevector-u8-ref separator i))
  64. (if (< offset end)
  65. (loop (1+ i))
  66. #t)
  67. #f)))
  68. #f)))
  69. (if (< bv-length separator-length)
  70. (list bv #f #f)
  71. (let ((found (let scan-at ((pos 0))
  72. (let ((byte (bytevector-u8-ref bv pos)))
  73. (if (and (eqv? byte separator-first)
  74. (at-separator? pos))
  75. pos
  76. (let ((next-pos (1+ pos)))
  77. (if (< next-pos bv-length)
  78. (scan-at next-pos)
  79. #f)))))))
  80. (if found
  81. (let* ((prefix (make-bytevector found))
  82. (suffix-start (+ found separator-length))
  83. (suffix-length (- bv-length suffix-start))
  84. (suffix (make-bytevector suffix-length)))
  85. (bytevector-copy! bv 0 prefix 0 found)
  86. (bytevector-copy! bv suffix-start suffix 0 suffix-length)
  87. (list prefix separator suffix))
  88. (list bv #f #f)))))