encode.ts 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. export function base64Encode(value: string) {
  2. const bytes = new TextEncoder().encode(value)
  3. const binary = Array.from(bytes, (b) => String.fromCharCode(b)).join("")
  4. return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "")
  5. }
  6. export function base64Decode(value: string) {
  7. const binary = atob(value.replace(/-/g, "+").replace(/_/g, "/"))
  8. const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0))
  9. return new TextDecoder().decode(bytes)
  10. }
  11. export async function hash(content: string, algorithm = "SHA-256"): Promise<string> {
  12. const encoder = new TextEncoder()
  13. const data = encoder.encode(content)
  14. const hashBuffer = await crypto.subtle.digest(algorithm, data)
  15. const hashArray = Array.from(new Uint8Array(hashBuffer))
  16. const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("")
  17. return hashHex
  18. }
  19. export function checksum(content: string): string | undefined {
  20. if (!content) return undefined
  21. let hash = 0x811c9dc5
  22. for (let i = 0; i < content.length; i++) {
  23. hash ^= content.charCodeAt(i)
  24. hash = Math.imul(hash, 0x01000193)
  25. }
  26. return (hash >>> 0).toString(36)
  27. }
  28. export function sampledChecksum(content: string, limit = 500_000): string | undefined {
  29. if (!content) return undefined
  30. if (content.length <= limit) return checksum(content)
  31. const size = 4096
  32. const points = [
  33. 0,
  34. Math.floor(content.length * 0.25),
  35. Math.floor(content.length * 0.5),
  36. Math.floor(content.length * 0.75),
  37. content.length - size,
  38. ]
  39. const hashes = points
  40. .map((point) => {
  41. const start = Math.max(0, Math.min(content.length - size, point - Math.floor(size / 2)))
  42. return checksum(content.slice(start, start + size)) ?? ""
  43. })
  44. .join(":")
  45. return `${content.length}:${hashes}`
  46. }