diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 14159b7..50b5427 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,50 +1,229 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: - push: - branches: [main, master] - pull_request: - branches: [main, master] + workflow_call: + inputs: + extra-packages: + type: string + default: "" + required: false + cache-version: + type: string + default: "2" + required: false + pandoc-version: + type: string + default: "3.x" + required: false + extra-check-args: + type: string + # default: '"--run-donttest", "--no-manual", "--as-cran"' + default: "NULL" + required: false + macOS: + type: string + default: "macOS-latest" + required: false + windows: + type: string + default: "windows-latest" + required: false + ubuntu: + type: string + required: false + # To test more versions, they must be separated by a space. Ex: `"ubuntu-18.04 ubuntu-20.04` + default: "ubuntu-20.04" + minimum-r-version: + type: string + required: false + default: "" + force-windows-src: + type: boolean + required: false + default: false + rtools-35: + type: boolean + default: true + required: false + rtools-40: + type: boolean + default: true + required: false name: R-CMD-check jobs: + setup: + name: setup + runs-on: ubuntu-latest + outputs: + config: ${{ steps.config.outputs.config }} + steps: + # - name: devel + # id: devel + # uses: r-lib/actions/setup-r@v2 + # with: + # r-version: devel + # install-r: false + + - name: release + id: release + uses: r-lib/actions/setup-r@v2 + with: + r-version: release + install-r: false + + - name: oldrel-1 + id: oldrel-1 + uses: r-lib/actions/setup-r@v2 + with: + r-version: oldrel-1 + install-r: false + + - name: oldrel-2 + id: oldrel-2 + uses: r-lib/actions/setup-r@v2 + with: + r-version: oldrel-2 + install-r: false + + - name: oldrel-3 + id: oldrel-3 + uses: r-lib/actions/setup-r@v2 + with: + r-version: oldrel-3 + install-r: false + + - name: oldrel-4 + id: oldrel-4 + uses: r-lib/actions/setup-r@v2 + with: + r-version: oldrel-4 + install-r: false + + - name: Checkout GitHub repo + uses: rstudio/shiny-workflows/.github/internal/checkout@v1 + + # R is a pre-installed software + - name: Config + id: config + shell: Rscript {0} + run: | + mac <- "${{ inputs.macOS }}" + windows <- "${{ inputs.windows }}" + ubuntu <- strsplit("${{ inputs.ubuntu }}", "[[:space:],]+")[[1]] + has_src <- dir.exists("src") + min_r_ver <- "${{ inputs.minimum-r-version }}" + test_on_rtools35 <- identical("${{ inputs.rtools-35 }}", "true") + test_on_rtools40 <- identical("${{ inputs.rtools-40 }}", "true") + force_windows_src <- identical("${{ inputs.force-windows-src }}", "true") + if (force_windows_src) has_src <- TRUE + + rver <- list( + # devel = "${{ steps.devel.outputs.installed-r-version }}", + # When R 4.3 was released, R version 4.4.0 was not recognized. + # However, `"devel"` is recognized within `r-lib/actions/setup-r`. + devel = "devel", + release = "${{ steps.release.outputs.installed-r-version }}", + oldrel1 = "${{ steps.oldrel-1.outputs.installed-r-version }}", + oldrel2 = "${{ steps.oldrel-2.outputs.installed-r-version }}", + oldrel3 = "${{ steps.oldrel-3.outputs.installed-r-version }}", + oldrel4 = "${{ steps.oldrel-4.outputs.installed-r-version }}" + ) + job <- function(os, r, ...) { + list(os = os, r = r, ...) + } + is_valid_os <- function(os, r_ver = "") { + if (identical(os, "false")) return(FALSE) + if (identical(os, "")) return(FALSE) + if (any(nchar(c(r_ver, min_r_ver)) == 0)) return(TRUE) + if (identical(r_ver, "devel")) return(TRUE) + r_ver >= min_r_ver + } + config <- c( + list( + if (is_valid_os(mac, rver$release)) job(mac, rver$release), + if (has_src && is_valid_os(windows, "devel")) job(windows, "devel", "rtools-version" = "44"), + if (is_valid_os(windows, rver$release)) job(windows, rver$release, "rtools-version" = "43"), + if (has_src && is_valid_os(windows, "4.2")) job(windows, "4.2", "rtools-version" = "42"), + if (has_src && test_on_rtools40 && is_valid_os(windows, "4.1")) job(windows, "4.1"), + if (has_src && test_on_rtools35 && is_valid_os(windows, "3.6")) job(windows, "3.6"), + if (is_valid_os(ubuntu, rver$devel)) job(ubuntu[[1]], rver$devel, "http-user-agent" = "release") + ), + if (is_valid_os(ubuntu)) + unlist(recursive = FALSE, lapply(ubuntu, function(ubuntu_) { + list( + if (is_valid_os(ubuntu_, rver$release)) job(ubuntu_, rver$release), + if (is_valid_os(ubuntu_, rver$oldrel1)) job(ubuntu_, rver$oldrel1), + if (is_valid_os(ubuntu_, rver$oldrel2)) job(ubuntu_, rver$oldrel2), + if (is_valid_os(ubuntu_, rver$oldrel3)) job(ubuntu_, rver$oldrel3), + if (is_valid_os(ubuntu_, rver$oldrel4)) job(ubuntu_, rver$oldrel4) + ) + })) + ) + ## Drop NULLs + config <- config[!vapply(config, is.null, logical(1))] + ## Convert to JSON manually to save 10s installing `jsonlite` + join_and_wrap <- function(x, start, end, sep = ",") { + paste0(start, paste0(x, collapse = sep), end) + } + entries_json <- vapply(config, character(1), FUN = function(entry) { + join_and_wrap( + paste0("\"", names(entry), "\":\"", unname(entry), "\""), + "{", "}" + ) + }) + config_json <- join_and_wrap(entries_json, "[", "]") + cat("Config:\n", config_json, "\n", sep = "") + cat("config=", config_json, "\n", file = Sys.getenv("GITHUB_OUTPUT"), sep = "", append = TRUE) + R-CMD-check: runs-on: ${{ matrix.config.os }} name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + needs: [setup] strategy: fail-fast: false matrix: - config: - - {os: macos-latest, r: 'release'} - - {os: windows-latest, r: 'release'} - - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} - - {os: ubuntu-latest, r: 'release'} - - {os: ubuntu-latest, r: 'oldrel-1'} + config: ${{ fromJSON(needs.setup.outputs.config) }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v4 - - - uses: r-lib/actions/setup-pandoc@v2 + - name: Checkout GitHub repo + uses: rstudio/shiny-workflows/.github/internal/checkout@v1 - - uses: r-lib/actions/setup-r@v2 + - name: Install R, system dependencies, and package dependencies + uses: rstudio/shiny-workflows/setup-r-package@v1 with: + rtools-version: ${{ matrix.config.rtools-version }} + pandoc-version: ${{ inputs.pandoc-version }} r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} - use-public-rspm: true + cache-version: ${{ inputs.cache-version }} + needs: check + extra-packages: | + any::rcmdcheck + ${{ inputs.extra-packages }} - - uses: r-lib/actions/setup-r-dependencies@v2 + - name: Check package + uses: r-lib/actions/check-r-package@v2 + timeout-minutes: 30 with: - extra-packages: any::rcmdcheck - needs: check + check-dir: '"check"' # matches directory below + args: 'c(${{ inputs.extra-check-args }}, "--no-manual", "--as-cran")' - - uses: r-lib/actions/check-r-package@v2 + - name: "Show `testthat` output" + if: always() + run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + - name: "Show install logs" + if: always() + run: find check -name '00install.out' -exec cat '{}' \; || true + shell: bash + - name: "Upload 'Check package' results" + if: failure() + uses: actions/upload-artifact@main with: - upload-snapshots: true - build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' + name: ${{ matrix.config.os }}-r${{ matrix.config.r }}-results + path: "check" diff --git a/R/cpp11.R b/R/cpp11.R index 9555b6f..4acfc7d 100644 --- a/R/cpp11.R +++ b/R/cpp11.R @@ -1,17 +1,17 @@ # Generated by cpp11: do not edit by hand -compressToEncodedURIComponent_ <- function(uncompressed8) { - .Call(`_lzstringr_compressToEncodedURIComponent_`, uncompressed8) +compressToEncodedURIComponent_ <- function(bytes) { + .Call(`_lzstringr_compressToEncodedURIComponent_`, bytes) } -decompressFromEncodedURIComponent_ <- function(compressed8) { - .Call(`_lzstringr_decompressFromEncodedURIComponent_`, compressed8) +decompressFromEncodedURIComponent_ <- function(bytes) { + .Call(`_lzstringr_decompressFromEncodedURIComponent_`, bytes) } -compressToBase64_ <- function(uncompressed8) { - .Call(`_lzstringr_compressToBase64_`, uncompressed8) +compressToBase64_ <- function(bytes) { + .Call(`_lzstringr_compressToBase64_`, bytes) } -decompressFromBase64_ <- function(compressed8) { - .Call(`_lzstringr_decompressFromBase64_`, compressed8) +decompressFromBase64_ <- function(bytes) { + .Call(`_lzstringr_decompressFromBase64_`, bytes) } diff --git a/R/lzstringr-package.R b/R/lzstringr-package.R index 41c2dff..9dd4d8e 100644 --- a/R/lzstringr-package.R +++ b/R/lzstringr-package.R @@ -3,26 +3,78 @@ ## usethis namespace: end NULL -#' @export compressToBase64 -compressToBase64 <- function(string) { +safe_compress <- function(string, f) { string <- enc2utf8(string) - compressToBase64_(string) + string <- iconv(string, from="UTF-8", to="UTF-16", toRaw=TRUE)[[1]] + result <- f(string) + chr_result <- rawToChar(as.raw(result)) + chr_result } -#' @export decompressFromBase64 -decompressFromBase64 <- function(string) { +safe_decompress <- function(string, f) { string <- enc2utf8(string) - decompressFromBase64_(string) + string <- iconv(string, from="UTF-8", to="UTF-16", toRaw=TRUE)[[1]] + result <- f(string) + chr_result <- intToUtf8(result) + chr_result +} + +#' Compress a string to Base64 +#' +#' This function takes a string as input and returns a compressed version of the string in Base64 format. +#' +#' @param string A character string to be compressed. +#' @return A character string representing the compressed input string in Base64 format. +#' @export +#' @examples +#' \dontrun{ +#' compressToBase64("Hello, world!") +#' } +compressToBase64 <- function(string) { + safe_compress(string, compressToBase64_) } -#' @export compressToEncodedURIComponent +#' Decompress a string from Base64 +#' +#' This function takes a compressed string in Base64 format as input and returns the decompressed version of the string. +#' +#' @param string A character string in Base64 format to be decompressed. +#' @return A character string representing the decompressed input string. +#' @export +#' @examples +#' \dontrun{ +#' decompressFromBase64(compressed_string) +#' } +decompressFromBase64 <- function(string) { + safe_decompress(string, decompressFromBase64_) +} + +#' Compress a string to Encoded URI Component +#' +#' This function takes a string as input and returns a compressed version of the string in Encoded URI Component format. +#' +#' @param string A character string to be compressed. +#' @return A character string representing the compressed input string in Encoded URI Component format. +#' @export +#' @examples +#' \dontrun{ +#' compressToEncodedURIComponent("Hello, world!") +#' } compressToEncodedURIComponent <- function(string) { - string <- enc2utf8(string) - compressToEncodedURIComponent_(string) + safe_compress(string, compressToEncodedURIComponent_) } -#' @export decompressFromEncodedURIComponent +#' Decompress a string from Encoded URI Component +#' +#' This function takes a compressed string in Encoded URI Component format as input and returns the decompressed version of the string. +#' +#' @param string A character string in Encoded URI Component format to be decompressed. +#' @return A character string representing the decompressed input string. +#' @export +#' @examples +#' \dontrun{ +#' decompressFromEncodedURIComponent(compressed_string) +#' } decompressFromEncodedURIComponent <- function(string) { - string <- enc2utf8(string) - decompressFromEncodedURIComponent_(string) + safe_decompress(string, decompressFromEncodedURIComponent_) } diff --git a/README.Rmd b/README.Rmd index 0b50a80..45d650c 100644 --- a/README.Rmd +++ b/README.Rmd @@ -22,7 +22,7 @@ knitr::opts_chunk$set( -The goal of lzstringr is to provide an R wrapper for the [lzstring C++ library](https://github.com/andykras/lz-string-cpp). [lzstring](https://github.com/pieroxy/lz-string) is originally a JavaScript library that provides fast and efficient string compression and decompression using a [LZ-based algorithm](https://en.wikipedia.org/wiki/Lempel–Ziv–Welch). Credit goes to [Winston Chang](https://github.com/wch) for spotting this missing R package and doing the majority of the work over at the R Shinylive repo—check out his awesome contributions which this repo is based on [here](https://github.com/posit-dev/r-shinylive/issues/70) and [here](https://github.com/posit-dev/r-shinylive/pull/71). Also, shoutout to Andy Kras for his implementation in C++ of lzstring, which you can find right [here](https://github.com/andykras/lz-string-cpp), and [pieroxy](https://github.com/pieroxy), the original brain behind lzstring in JavaScript—peek at his work over [here](https://github.com/pieroxy/lz-string). +The goal of lzstringr is to provide an R wrapper for the [lzstring C++ library](https://github.com/andykras/lz-string-cpp). [lzstring](https://github.com/pieroxy/lz-string) is originally a JavaScript library that provides fast and efficient string compression and decompression using a [LZ-based algorithm](https://en.wikipedia.org/wiki/Lempel–Ziv–Welch). Credit goes to [Winston Chang](https://github.com/wch) for spotting this missing R package and guiding me over at the R Shinylive repo—check out his awesome contributions which this repo is based on [here](https://github.com/posit-dev/r-shinylive/issues/70) and [here](https://github.com/posit-dev/r-shinylive/pull/71). Also, shoutout to Andy Kras for his implementation in C++ of lzstring, which you can find right [here](https://github.com/andykras/lz-string-cpp), and [pieroxy](https://github.com/pieroxy), the original brain behind lzstring in JavaScript—peek at his work over [here](https://github.com/pieroxy/lz-string). ## Installation diff --git a/README.md b/README.md index 871f8ab..c640462 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ JavaScript library that provides fast and efficient string compression and decompression using a [LZ-based algorithm](https://en.wikipedia.org/wiki/Lempel–Ziv–Welch). Credit goes to [Winston Chang](https://github.com/wch) for spotting this missing R -package and doing the majority of the work over at the R Shinylive -repo—check out his awesome contributions which this repo is based on +package and guiding me over at the R Shinylive repo—check out his +awesome contributions which this repo is based on [here](https://github.com/posit-dev/r-shinylive/issues/70) and [here](https://github.com/posit-dev/r-shinylive/pull/71). Also, shoutout to Andy Kras for his implementation in C++ of lzstring, which you can diff --git a/man/compressToBase64.Rd b/man/compressToBase64.Rd new file mode 100644 index 0000000..481d40c --- /dev/null +++ b/man/compressToBase64.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lzstringr-package.R +\name{compressToBase64} +\alias{compressToBase64} +\title{Compress a string to Base64} +\usage{ +compressToBase64(string) +} +\arguments{ +\item{string}{A character string to be compressed.} +} +\value{ +A character string representing the compressed input string in Base64 format. +} +\description{ +This function takes a string as input and returns a compressed version of the string in Base64 format. +} +\examples{ +\dontrun{ +compressToBase64("Hello, world!") +} +} diff --git a/man/compressToEncodedURIComponent.Rd b/man/compressToEncodedURIComponent.Rd new file mode 100644 index 0000000..e1bdc4d --- /dev/null +++ b/man/compressToEncodedURIComponent.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lzstringr-package.R +\name{compressToEncodedURIComponent} +\alias{compressToEncodedURIComponent} +\title{Compress a string to Encoded URI Component} +\usage{ +compressToEncodedURIComponent(string) +} +\arguments{ +\item{string}{A character string to be compressed.} +} +\value{ +A character string representing the compressed input string in Encoded URI Component format. +} +\description{ +This function takes a string as input and returns a compressed version of the string in Encoded URI Component format. +} +\examples{ +\dontrun{ +compressToEncodedURIComponent("Hello, world!") +} +} diff --git a/man/decompressFromBase64.Rd b/man/decompressFromBase64.Rd new file mode 100644 index 0000000..a97d0db --- /dev/null +++ b/man/decompressFromBase64.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lzstringr-package.R +\name{decompressFromBase64} +\alias{decompressFromBase64} +\title{Decompress a string from Base64} +\usage{ +decompressFromBase64(string) +} +\arguments{ +\item{string}{A character string in Base64 format to be decompressed.} +} +\value{ +A character string representing the decompressed input string. +} +\description{ +This function takes a compressed string in Base64 format as input and returns the decompressed version of the string. +} +\examples{ +\dontrun{ +decompressFromBase64(compressed_string) +} +} diff --git a/man/decompressFromEncodedURIComponent.Rd b/man/decompressFromEncodedURIComponent.Rd new file mode 100644 index 0000000..958ece4 --- /dev/null +++ b/man/decompressFromEncodedURIComponent.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lzstringr-package.R +\name{decompressFromEncodedURIComponent} +\alias{decompressFromEncodedURIComponent} +\title{Decompress a string from Encoded URI Component} +\usage{ +decompressFromEncodedURIComponent(string) +} +\arguments{ +\item{string}{A character string in Encoded URI Component format to be decompressed.} +} +\value{ +A character string representing the decompressed input string. +} +\description{ +This function takes a compressed string in Encoded URI Component format as input and returns the decompressed version of the string. +} +\examples{ +\dontrun{ +decompressFromEncodedURIComponent(compressed_string) +} +} diff --git a/src/code.cpp b/src/code.cpp index 7569775..ad2b5f2 100644 --- a/src/code.cpp +++ b/src/code.cpp @@ -1,57 +1,72 @@ #include using namespace cpp11; #include -#include "lz-string.hpp" +#include "lz-string.h" +#include +#include +#include + +std::u16string createUTF16String(const std::vector& bytes) { + if (bytes.size() < 2) { + throw std::runtime_error("Invalid byte array. Size must be at least 2 bytes."); + } + + // Check byte order mark (BOM) + bool isLittleEndian = (bytes[0] == 0xFF && bytes[1] == 0xFE); + bool isBigEndian = (bytes[0] == 0xFE && bytes[1] == 0xFF); + + if (!isLittleEndian && !isBigEndian) { + throw std::runtime_error("Invalid byte order mark (BOM)."); + } + + std::u16string result; + for (size_t i = 2; i < bytes.size(); i += 2) { + char16_t codeUnit; + if (isLittleEndian) { + codeUnit = static_cast(bytes[i] | (bytes[i + 1] << 8)); + } else { + codeUnit = static_cast((bytes[i] << 8) | bytes[i + 1]); + } + result.push_back(codeUnit); + } + + return result; +} + [[cpp11::register]] -std::string compressToEncodedURIComponent_(std::string uncompressed8) { - std::wstring_convert, char16_t> converter_8_to_16; - std::u16string uncompressed16 = converter_8_to_16.from_bytes(uncompressed8); +std::u16string compressToEncodedURIComponent_(std::vector bytes) { + std::u16string uncompressed16 = createUTF16String(bytes); auto compressed16 = lzstring::compressToEncodedURIComponent(uncompressed16); - std::wstring_convert, char16_t> converter_16_to_8; - std::string compressed8 = converter_16_to_8.to_bytes(compressed16); - - return compressed8; + return compressed16; } [[cpp11::register]] -std::string decompressFromEncodedURIComponent_(std::string compressed8) { - std::wstring_convert, char16_t> converter_8_to_16; - std::u16string compressed16 = converter_8_to_16.from_bytes(compressed8); +std::u16string decompressFromEncodedURIComponent_(std::vector bytes) { + std::u16string compressed16 = createUTF16String(bytes); auto uncompressed16 = lzstring::decompressFromEncodedURIComponent(compressed16); - std::wstring_convert, char16_t> converter_16_to_8; - std::string uncompressed8 = converter_16_to_8.to_bytes(uncompressed16); - - return uncompressed8; + return uncompressed16; } [[cpp11::register]] -std::string compressToBase64_(std::string uncompressed8) { - std::wstring_convert, char16_t> converter_8_to_16; - std::u16string uncompressed16 = converter_8_to_16.from_bytes(uncompressed8); +std::u16string compressToBase64_(std::vector bytes) { + std::u16string uncompressed16 = createUTF16String(bytes); auto compressed16 = lzstring::compressToBase64(uncompressed16); - std::wstring_convert, char16_t> converter_16_to_8; - std::string compressed8 = converter_16_to_8.to_bytes(compressed16); - - return compressed8; + return compressed16; } [[cpp11::register]] -std::string decompressFromBase64_(std::string compressed8) { - std::wstring_convert, char16_t> converter_8_to_16; - std::u16string compressed16 = converter_8_to_16.from_bytes(compressed8); +std::u16string decompressFromBase64_(std::vector bytes) { + std::u16string compressed16 = createUTF16String(bytes); auto uncompressed16 = lzstring::decompressFromBase64(compressed16); - std::wstring_convert, char16_t> converter_16_to_8; - std::string uncompressed8 = converter_16_to_8.to_bytes(uncompressed16); - - return uncompressed8; + return uncompressed16; } diff --git a/src/cpp11.cpp b/src/cpp11.cpp index acd1840..a7e1bdb 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -6,31 +6,31 @@ #include // code.cpp -std::string compressToEncodedURIComponent_(std::string uncompressed8); -extern "C" SEXP _lzstringr_compressToEncodedURIComponent_(SEXP uncompressed8) { +std::u16string compressToEncodedURIComponent_(std::vector bytes); +extern "C" SEXP _lzstringr_compressToEncodedURIComponent_(SEXP bytes) { BEGIN_CPP11 - return cpp11::as_sexp(compressToEncodedURIComponent_(cpp11::as_cpp>(uncompressed8))); + return cpp11::as_sexp(compressToEncodedURIComponent_(cpp11::as_cpp>>(bytes))); END_CPP11 } // code.cpp -std::string decompressFromEncodedURIComponent_(std::string compressed8); -extern "C" SEXP _lzstringr_decompressFromEncodedURIComponent_(SEXP compressed8) { +std::u16string decompressFromEncodedURIComponent_(std::vector bytes); +extern "C" SEXP _lzstringr_decompressFromEncodedURIComponent_(SEXP bytes) { BEGIN_CPP11 - return cpp11::as_sexp(decompressFromEncodedURIComponent_(cpp11::as_cpp>(compressed8))); + return cpp11::as_sexp(decompressFromEncodedURIComponent_(cpp11::as_cpp>>(bytes))); END_CPP11 } // code.cpp -std::string compressToBase64_(std::string uncompressed8); -extern "C" SEXP _lzstringr_compressToBase64_(SEXP uncompressed8) { +std::u16string compressToBase64_(std::vector bytes); +extern "C" SEXP _lzstringr_compressToBase64_(SEXP bytes) { BEGIN_CPP11 - return cpp11::as_sexp(compressToBase64_(cpp11::as_cpp>(uncompressed8))); + return cpp11::as_sexp(compressToBase64_(cpp11::as_cpp>>(bytes))); END_CPP11 } // code.cpp -std::string decompressFromBase64_(std::string compressed8); -extern "C" SEXP _lzstringr_decompressFromBase64_(SEXP compressed8) { +std::u16string decompressFromBase64_(std::vector bytes); +extern "C" SEXP _lzstringr_decompressFromBase64_(SEXP bytes) { BEGIN_CPP11 - return cpp11::as_sexp(decompressFromBase64_(cpp11::as_cpp>(compressed8))); + return cpp11::as_sexp(decompressFromBase64_(cpp11::as_cpp>>(bytes))); END_CPP11 } diff --git a/src/lz-string.hpp b/src/lz-string.h similarity index 100% rename from src/lz-string.hpp rename to src/lz-string.h