Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions src/exe/cimbar_recv2/recv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,28 @@ int main(int argc, char** argv)
// attempt save
uint32_t fileId = res;

unsigned size = cimbard_get_filesize(fileId);
std::string filename = fmt::format("0.{}", size);
std::cerr << "Saving file " << filename << " of size " << size << std::endl;
int size = cimbard_get_filesize(fileId);

std::string filename;
filename.resize(255, '\0');
int fnsize = cimbard_get_filename(fileId, filename.data(), filename.size());
if (fnsize > 0)
filename.resize(fnsize);
else // fallback
filename = fmt::format("0.{}", size);
std::cerr << "Saving file " << filename << " of (compressed) size " << size << std::endl;

std::string file_path = fmt::format("{}/{}", outpath, filename);
std::ofstream outs(file_path, std::ios::binary);

std::vector<unsigned char> data;
data.resize(size);
int res = cimbard_finish_copy(fileId, data.data(), size);
if (res != 0)
std::cerr << "failed fountain_finish_copy " << res << std::endl;
data.resize(cimbard_get_decompress_bufsize());

decompress_on_store<std::ofstream>(outpath, true)(filename, data);
int res = 1;
while ((res = cimbard_decompress_read(fileId, data.data(), data.size())) > 0)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually using the full api here now.

outs.write(reinterpret_cast<const char*>(data.data()), res);
if (res < 0)
std::cerr << "failed cimbard_decompress_read " << res << std::endl;
}
}

Expand Down
10 changes: 3 additions & 7 deletions src/lib/cimbar_js/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ set(SOURCES

cimbar_recv_js.h
cimbar_recv_js.cpp
cimbar_zstd_js.h
cimbar_zstd_js.cpp
)
endif()

Expand Down Expand Up @@ -66,16 +64,14 @@ set(LINK_WASM_EXPORTED_FUNCTIONS
${LINK_WASM_EXPORTED_FUNCTIONS}

, "_cimbard_get_report"
, "_cimbard_get_bufsize"
, "_cimbard_scan_extract_decode"
, "_cimbard_fountain_decode"
, "_cimbard_get_bufsize"
, "_cimbard_get_filesize"
, "_cimbard_get_filename"
, "_cimbard_finish_copy"
, "_cimbard_get_decompress_bufsize"
, "_cimbard_decompress_read"
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wasm export list acts as a public api reference for the moment...

, "_cimbard_configure_decode"
, "_cimbarz_init_decompress"
, "_cimbarz_get_bufsize"
, "_cimbarz_decompress_read"
)
endif()

Expand Down
104 changes: 92 additions & 12 deletions src/lib/cimbar_js/cimbar_recv_js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@


namespace {

// for decode
std::shared_ptr<fountain_decoder_sink> _sink;
std::string _reporting;

// for decompress
// we support only one decompress at a time!
uint32_t _decId = 0;
std::vector<uchar> _reassembled;
std::unique_ptr<cimbar::zstd_decompressor<std::stringstream>> _dec;

std::string _reporting;
cv::Mat _debugFrame;

TimeAccumulator _tScanExtract;
Expand All @@ -31,6 +37,48 @@ namespace {
// settings
int _modeVal = 68;

// set up stateful decompressor
// for api simplicity, this is coupled to recover_contents()
// ... but we *could* split them up
int init_decompress(uint32_t id)
{
if (id != _decId)
return -11;
if (_dec)
_dec.reset();
_dec = std::make_unique<cimbar::zstd_decompressor<std::stringstream>>();
if (!_dec)
return -12;
_dec->init_decompress(reinterpret_cast<char*>(_reassembled.data()), _reassembled.size());
return 0;
}

// recovers file contents into _reassembled, and sets _decId = id if so.
// if the contents cannot be recovered, amounts to a no-op with error
int recover_contents(uint32_t id)
{
if (id != _decId)
{
if (!_sink)
return -1;
if (_sink->is_done(id))
return -2; // it's gone man

_reassembled.resize(cimbard_get_filesize(id));
if (!_sink->recover(id, _reassembled.data(), _reassembled.size()))
return -3;
_decId = id;

int res = init_decompress(id);
if (res < 0)
return res;
}
if (_reassembled.empty())
return -5;

return 0;
}

unsigned fountain_chunks_per_frame()
{
return cimbar::Config::fountain_chunks_per_frame(
Expand Down Expand Up @@ -166,14 +214,24 @@ int64_t cimbard_fountain_decode(const unsigned char* buffer, unsigned size)
return res;
}

int cimbard_get_filesize(uint32_t id)
// mostly for internal use, but also helpful for debugging
unsigned cimbard_get_filesize(uint32_t id)
{
FountainMetadata md(id);
return md.file_size();
}

int cimbard_get_filename(const uchar* finbuffer, unsigned size, char* filename, unsigned fnsize)
// do recover() if does not exist (fail with appropriate neg values), if it does use the bytes.
// stateful against a map (same as cimbard_decompress_read()
int cimbard_get_filename(uint32_t id, char* filename, unsigned fnsize)
{
int res = recover_contents(id);
if (res < 0)
return res;

const uchar* finbuffer = _reassembled.data();
unsigned size = _reassembled.size();

std::string fn = cimbar::zstd_header_check::get_filename(finbuffer, size);
if (!fn.empty())
fn = File::basename(fn);
Expand All @@ -186,15 +244,29 @@ int cimbard_get_filename(const uchar* finbuffer, unsigned size, char* filename,
return fn.size();
}

// if fountain_decode returned a >0 value, call this to retrieve the reassembled file
// bouth fountain_*() calls should be from the same js webworker/thread
int cimbard_finish_copy(uint32_t id, uchar* buffer, unsigned size)
int cimbard_decompress_read(uint32_t id, unsigned char* buffer, unsigned size)
{
if (!_sink)
return -1;
if (!_sink->recover(id, buffer, size))
return -2;
return 0;
int res = recover_contents(id);
Copy link
Owner Author

@sz3 sz3 Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notably, both decompress_read() and get_filename() will call recover_contents() (the result will be cached), since they both need to pull the data from the zstd stream. Definitionally, then, you can only call either after cimbard_fountain_decode() has finished reassembling the file.

if (res < 0)
return res;

if (!_dec)
return -13;
if (!_dec->good())
return -14;

_dec->str(std::string());
_dec->write_once();
std::string temp = _dec->str();
if (size > temp.size())
size = temp.size();
std::copy(temp.data(), temp.data()+size, buffer);
return size;
}

int cimbard_get_decompress_bufsize()
{
return ZSTD_DStreamOutSize();
}

int cimbard_configure_decode(int mode_val)
Expand All @@ -215,4 +287,12 @@ int cimbard_configure_decode(int mode_val)
return 0;
}

// testing
unsigned char* cimbard_get_reassembled_file_buff()
{
if (_reassembled.empty())
return nullptr;
return _reassembled.data();
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing only, please

}

}
26 changes: 15 additions & 11 deletions src/lib/cimbar_js/cimbar_recv_js.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,24 @@ int cimbard_scan_extract_decode(const unsigned char* imgdata, unsigned imgw, uns
// persists state, the return value (if >0) corresponds to a uint32_t id
int64_t cimbard_fountain_decode(const unsigned char* buffer, unsigned size);

// get filesize from id
int cimbard_get_filesize(uint32_t id);

// if fountain_decode returned a >0 value, call this to retrieve the reassembled file
// wherever a uint32_t id is passed, it should be on the same js thread
// ... or at least in the same js shared memory...
// as the fountain_decode() call
int cimbard_finish_copy(uint32_t id, unsigned char* finbuffer, unsigned size);

// get filename from reassembled file
int cimbard_get_filename(const unsigned char* finbuffer, unsigned size, char* filename, unsigned fnsize);
// get compressed filesize from id
// you probably don't need to use this.
unsigned cimbard_get_filesize(uint32_t id);

// if fountain_decode returned a >0 value,
// get filename and (partial) contents from reassembled file
// wherever a uint32_t id is passed, it should be in the
// same js shared memory as the fountain_decode() call
// cimbard_decompress_read() will return 0 when all file contents have been read
int cimbard_get_filename(uint32_t id, char* filename, unsigned fnsize);
int cimbard_get_decompress_bufsize();
int cimbard_decompress_read(uint32_t id, unsigned char* buffer, unsigned size);

int cimbard_configure_decode(int mode_val);

// testing usage only!
unsigned char* cimbard_get_reassembled_file_buff();

#ifdef __cplusplus
}
#endif
Expand Down
49 changes: 0 additions & 49 deletions src/lib/cimbar_js/cimbar_zstd_js.cpp

This file was deleted.

20 changes: 0 additions & 20 deletions src/lib/cimbar_js/cimbar_zstd_js.h

This file was deleted.

17 changes: 3 additions & 14 deletions src/lib/cimbar_js/test/cimbar_jsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "cimb_translator/Config.h"
#include "cimbar_js/cimbar_js.h"
#include "cimbar_js/cimbar_recv_js.h"
#include "cimbar_js/cimbar_zstd_js.h"
#include "serialize/format.h"

#include <iostream>
Expand Down Expand Up @@ -55,27 +54,17 @@ TEST_CASE( "cimbar_jsTest/testRoundtrip", "[unit]" )
{
uint32_t fileId = res;

unsigned size = cimbard_get_filesize(fileId);
assertEquals( 5282, size );

std::vector<unsigned char> data;
data.resize(size);
int res = cimbard_finish_copy(fileId, data.data(), size);
assertEquals( 0, res );

std::string actualFilename;
actualFilename.resize(255);
int fnsz = cimbard_get_filename(data.data(), size, actualFilename.data(), actualFilename.size());
int fnsz = cimbard_get_filename(fileId, actualFilename.data(), actualFilename.size());
assertEquals( 21, fnsz );
actualFilename.resize(fnsz);
assertEquals( "foobar-c语言版.txt", actualFilename );

assertEquals(0, cimbarz_init_decompress(data.data(), data.size()));

std::vector<unsigned char> zstdbuff;
zstdbuff.resize(cimbarz_get_bufsize());
zstdbuff.resize(cimbard_get_decompress_bufsize());

int outsize = cimbarz_decompress_read(zstdbuff.data(), zstdbuff.size());
int outsize = cimbard_decompress_read(fileId, zstdbuff.data(), zstdbuff.size());
assertEquals(contents.size(), outsize);
std::string_view finalOutput{reinterpret_cast<char*>(zstdbuff.data()), contents.size()};

Expand Down
Loading