#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <string>
#include "sass.h"
#include "crc.h"
#include "md5.h"
#define BUFFERSIZE 1024
#include "b64/encode.hpp"
std::string md5s(const std::string& text, struct Sass_Compiler* comp)
{
MD5 digester;
digester.update(text.c_str(), text.length());
digester.finalize();
return digester.hexdigest();
}
union Sass_Value* file_not_found(const std::string& file)
{
std::string err("File not found: ");
err += file; // add the filename
return sass_make_error(err.c_str());
}
union Sass_Value* md5f(const std::string& file, struct Sass_Compiler* comp)
{
char *path = sass_compiler_find_file(file.c_str(), comp);
if (*path == '\0') {
std::free(path);
return sass_make_error("No filename given");
}
else {
char in[1024];
MD5 digester;
std::ifstream fh;
fh.open(path, std::ios::binary);
std::free(path);
if (fh.fail()) return file_not_found(file);
while(fh.read(in, sizeof(in))) {
std::streamsize s = fh.gcount();
digester.update(in, s);
}
std::streamsize s = fh.gcount();
digester.update(in, s);
digester.finalize();
std::string rv(digester.hexdigest());
return sass_make_string(rv.c_str());
}
}
std::string crc16s(const std::string& text, struct Sass_Compiler* comp)
{
short int crc = 0xFFFF;
crc = crc16(text.c_str(), text.length(), crc);
std::stringstream ss;
ss << std::setfill('0')
<< std::setw(2)
<< std::hex
<< ((crc & 0x00FF) >> 0)
<< ((crc & 0xFF00) >> 8);
return ss.str();
}
std::string crc32s(const std::string& text, struct Sass_Compiler* comp)
{
unsigned long int crc = 0xFFFFFFFF;
crc = crc32buf(text.c_str(), text.length(), crc);
std::stringstream ss;
ss << std::setfill('0')
<< std::setw(8)
<< std::hex
<< (0xFFFFFFFF & crc);
return ss.str();
}
union Sass_Value* crc16f(const std::string& file, struct Sass_Compiler* comp)
{
char *path = sass_compiler_find_file(file.c_str(), comp);
if (*path == '\0') {
std::free(path);
return sass_make_error("No filename given");
}
else {
char in[1024];
std::ifstream fh;
short int crc = 0xFFFF;
fh.open(path, std::ios::binary);
std::free(path);
if (fh.fail()) return file_not_found(file);
while(fh.read(in, sizeof(in))) {
std::streamsize s = fh.gcount();
crc = crc16(in, s, crc);
}
std::streamsize s = fh.gcount();
crc = crc16(in, s, crc);
std::stringstream ss;
ss << std::setfill('0')
<< std::setw(2)
<< std::hex
<< ((crc & 0x00FF) >> 0)
<< ((crc & 0xFF00) >> 8);
std::string rv(ss.str());
return sass_make_string(rv.c_str());
}
}
union Sass_Value* crc32f(const std::string& file, struct Sass_Compiler* comp)
{
char *path = sass_compiler_find_file(file.c_str(), comp);
if (*path == '\0') {
std::free(path);
return sass_make_error("No filename given");
}
else {
char in[1024];
std::ifstream fh;
unsigned long int crc = 0xFFFFFFFF;
fh.open(path, std::ios::binary);
std::free(path);
if (fh.fail()) return file_not_found(file);
while(fh.read(in, sizeof(in))) {
std::streamsize s = fh.gcount();
crc = crc32buf(in, s, crc);
}
std::streamsize s = fh.gcount();
crc = crc32buf(in, s, crc);
std::stringstream ss;
ss << std::setfill('0')
<< std::setw(8)
<< std::hex
<< (0xFFFFFFFF & crc);
std::string rv(ss.str());
return sass_make_string(rv.c_str());
}
}
std::string base64s(const std::string& text, struct Sass_Compiler* comp)
{
int len = 0;
char out[1368];
size_t size = 1024;
base64::encoder enc;
std::stringstream ss;
const char* in = text.c_str();
for (size_t i = 0, L = text.length(); i < L; i += size) {
if (L < i + size) size = L - i;
len = enc.encode(in, size, out);
ss << std::string(out, out + len);
in += size;
}
// finalize base64 string
len = enc.encode_end(out);
ss << std::string(out, out + len);
// return string instance
return ss.str();
}
union Sass_Value* base64f(const std::string& file, struct Sass_Compiler* comp)
{
char *path = sass_compiler_find_file(file.c_str(), comp);
if (*path == '\0') {
std::free(path);
return sass_make_error("No filename given");
}
else {
int len = 0;
char in[1024];
char out[1368];
std::ifstream fh;
base64::encoder enc;
fh.open(path, std::ios::binary);
std::free(path);
if (fh.fail()) return file_not_found(file);
std::stringstream ss;
// read into chunks
while(fh.read(in, sizeof(in))) {
// encode the readed part
std::streamsize s = fh.gcount();
len = enc.encode(in, s, out);
ss << std::string(out, out + len);
}
// encode the final part
std::streamsize s = fh.gcount();
len = enc.encode(in, s, out);
ss << std::string(out, out + len);
// finalize base64 string
len = enc.encode_end(out);
ss << std::string(out, out + len);
// return string instance
std::string rv(ss.str());
return sass_make_string(rv.c_str());
}
}
// most functions are very simple
#define IMPLEMENT_STR_FN(fn) \
union Sass_Value* fn_##fn(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp) \
{ \
if (!sass_value_is_list(s_args)) { \
return sass_make_error("Invalid arguments for " #fn); \
} \
if (sass_list_get_length(s_args) != 1) { \
return sass_make_error("Exactly one arguments expected for " #fn); \
} \
const union Sass_Value* inp = sass_list_get_value(s_args, 0); \
if (!sass_value_is_string(inp)) { \
return sass_make_error("You must pass a string into " #fn); \
} \
const char* inp_str = sass_string_get_value(inp); \
std::string rv = fn(inp_str, comp); \
return sass_make_string(rv.c_str()); \
} \
// string digest functions
IMPLEMENT_STR_FN(md5s)
IMPLEMENT_STR_FN(crc16s)
IMPLEMENT_STR_FN(crc32s)
IMPLEMENT_STR_FN(base64s)
// most functions are very simple
#define IMPLEMENT_FILE_FN(fn) \
union Sass_Value* fn_##fn(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp) \
{ \
if (!sass_value_is_list(s_args)) { \
return sass_make_error("Invalid arguments for " #fn); \
} \
if (sass_list_get_length(s_args) != 1) { \
return sass_make_error("Exactly one arguments expected for " #fn); \
} \
const union Sass_Value* inp = sass_list_get_value(s_args, 0); \
if (!sass_value_is_string(inp)) { \
return sass_make_error("You must pass a string into " #fn); \
} \
const char* inp_str = sass_string_get_value(inp); \
return fn(inp_str, comp); \
} \
// file digest functions
IMPLEMENT_FILE_FN(md5f)
IMPLEMENT_FILE_FN(crc16f)
IMPLEMENT_FILE_FN(crc32f)
IMPLEMENT_FILE_FN(base64f)
// return version of libsass we are linked against
extern "C" const char* ADDCALL libsass_get_version() {
return libsass_version();
}
// entry point for libsass to request custom functions from plugin
extern "C" Sass_Function_List ADDCALL libsass_load_functions()
{
// create list of all custom functions
Sass_Function_List fn_list = sass_make_function_list(8);
// string digest functions
sass_function_set_list_entry(fn_list, 0, sass_make_function("md5($x)", fn_md5s, 0));
sass_function_set_list_entry(fn_list, 1, sass_make_function("crc16($x)", fn_crc16s, 0));
sass_function_set_list_entry(fn_list, 2, sass_make_function("crc32($x)", fn_crc32s, 0));
sass_function_set_list_entry(fn_list, 3, sass_make_function("base64($x)", fn_base64s, 0));
// file digest functions
sass_function_set_list_entry(fn_list, 4, sass_make_function("md5f($x)", fn_md5f, 0));
sass_function_set_list_entry(fn_list, 5, sass_make_function("crc16f($x)", fn_crc16f, 0));
sass_function_set_list_entry(fn_list, 6, sass_make_function("crc32f($x)", fn_crc32f, 0));
sass_function_set_list_entry(fn_list, 7, sass_make_function("base64f($x)", fn_base64f, 0));
// return the list
return fn_list;
}
// entry point for libsass to request custom headers from plugin
extern "C" Sass_Importer_List ADDCALL libsass_load_headers()
{
// create list of all custom functions
Sass_Importer_List imp_list = sass_make_importer_list(1);
// put the only function in this plugin to the list
sass_importer_set_list_entry(imp_list, 0, 0);
// return the list
return imp_list;
}