#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#include <google/vcdecoder.h>
#include <google/vcencoder.h>
#include <memory>
// FIXME: figure out the right value for this: maybe dynamic?
#define BUF_SIZE 65536
int encode(SV *source_sv, int input_fd, SV *input_sv, int output_fd, SV *output_sv) {
std::auto_ptr<open_vcdiff::HashedDictionary> hashed_dictionary;
char *source_str;
size_t source_str_size;
source_str_size = SvCUR(source_sv);
source_str = SvPV(source_sv, source_str_size);
hashed_dictionary.reset(new open_vcdiff::HashedDictionary(source_str, source_str_size));
if (!hashed_dictionary->Init()) {
return 1;
}
open_vcdiff::VCDiffFormatExtensionFlags format_flags = open_vcdiff::VCD_STANDARD_FORMAT;
open_vcdiff::VCDiffStreamingEncoder encoder(hashed_dictionary.get(), format_flags, false);
std::string output_string;
if (!encoder.StartEncoding(&output_string)) {
return 2;
}
char *ibuf_ptr = NULL;
std::string ibuf_str;
size_t ibuf_len = 0;
char *input_str_ptr = NULL;
size_t input_str_size = 0;
if (input_fd != -1) {
ibuf_str.resize(BUF_SIZE);
} else {
input_str_size = SvCUR(input_sv);
input_str_ptr = SvPV(input_sv, input_str_size);
ibuf_ptr = input_str_ptr;
}
while(1) {
if (input_fd != -1) {
ibuf_len = read(input_fd, &ibuf_str[0], BUF_SIZE);
if (ibuf_len < 0) {
return 3;
}
} else {
ibuf_ptr += ibuf_len;
ibuf_len = MIN(BUF_SIZE, input_str_size - (ibuf_ptr - input_str_ptr));
}
if (ibuf_len == 0) break;
if (!encoder.EncodeChunk((input_fd != -1) ? &ibuf_str[0] : ibuf_ptr, ibuf_len, &output_string)) {
return 4;
}
if (output_fd != -1) {
if (output_string.length() && write(output_fd, output_string.c_str(), output_string.length()) != output_string.length()) {
return 5;
}
output_string.clear();
}
if (input_fd != -1 && ibuf_len < BUF_SIZE) break; // stream is empty
}
if (!encoder.FinishEncoding(&output_string)) {
return 6;
}
if (output_fd != -1) {
if (output_string.length() && write(output_fd, output_string.c_str(), output_string.length()) != output_string.length()) {
return 5;
}
output_string.clear();
} else {
sv_catpvn(output_sv, output_string.c_str(), output_string.length());
}
return 0;
}
int decode(SV *source_sv, int input_fd, SV *input_sv, int output_fd, SV *output_sv) {
open_vcdiff::VCDiffStreamingDecoder decoder;
char *source_str;
size_t source_str_size;
source_str_size = SvCUR(source_sv);
source_str = SvPV(source_sv, source_str_size);
decoder.StartDecoding(source_str, source_str_size);
std::string output_string;
char *ibuf_ptr = NULL;
std::string ibuf_str;
size_t ibuf_len = 0;
char *input_str_ptr = NULL;
size_t input_str_size = 0;
if (input_fd != -1) {
ibuf_str.resize(BUF_SIZE);
} else {
input_str_size = SvCUR(input_sv);
input_str_ptr = SvPV(input_sv, input_str_size);
ibuf_ptr = input_str_ptr;
}
while(1) {
if (input_fd != -1) {
ibuf_len = read(input_fd, &ibuf_str[0], BUF_SIZE);
if (ibuf_len < 0) {
return 3;
}
} else {
ibuf_ptr += ibuf_len;
ibuf_len = MIN(BUF_SIZE, input_str_size - (ibuf_ptr - input_str_ptr));
}
if (ibuf_len == 0) break;
if (!decoder.DecodeChunk((input_fd != -1) ? &ibuf_str[0] : ibuf_ptr, ibuf_len, &output_string)) {
return 7;
}
if (output_fd != -1) {
if (output_string.length() && write(output_fd, output_string.c_str(), output_string.length()) != output_string.length()) {
return 5;
}
output_string.clear();
}
if (input_fd != -1 && ibuf_len < BUF_SIZE) break; // stream is empty
}
if (!decoder.FinishDecoding()) {
return 7;
}
if (output_fd != -1) {
if (output_string.length() && write(output_fd, output_string.c_str(), output_string.length()) != output_string.length()) {
return 5;
}
output_string.clear();
} else {
sv_catpvn(output_sv, output_string.c_str(), output_string.length());
}
return 0;
}
MODULE = Vcdiff::OpenVcdiff PACKAGE = Vcdiff::OpenVcdiff
PROTOTYPES: ENABLE
int
_encode(source_sv, input_fd, input_sv, output_fd, output_sv)
SV *source_sv
int input_fd
SV *input_sv
int output_fd
SV *output_sv
CODE:
try {
RETVAL = encode(source_sv,
input_fd, input_sv,
output_fd, output_sv);
} catch(...) {
RETVAL = 9;
}
OUTPUT:
RETVAL
int
_decode(source_sv, input_fd, input_sv, output_fd, output_sv)
SV *source_sv
int input_fd
SV *input_sv
int output_fd
SV *output_sv
CODE:
try {
RETVAL = decode(source_sv,
input_fd, input_sv,
output_fd, output_sv);
} catch(...) {
RETVAL = 9;
}
OUTPUT:
RETVAL