12#define BDEBUG(...) Ase::debug ("blob", __VA_ARGS__)
17error_result (
String url,
int fallback_errno = EINVAL,
String msg =
"failed to load")
19 const int saved_errno =
errno ?
errno : fallback_errno;
20 BDEBUG (
"%s %s: %s", msg.c_str(),
CQUOTE (url), strerror (saved_errno));
33 explicit BlobImpl (
const String &name,
size_t dsize,
const char *data) :
34 name_ (name), size_ (dsize), data_ (data)
40 void operator() (
const char*) {}
51StringBlob::StringBlob (
const String &name,
const String &str) :
52 BlobImpl (name, str.size(), NULL), string_ (str)
54 data_ = string_.
data();
58template<
class Deleter>
64 explicit ByteBlob (
const String &name,
size_t dsize,
const char *data,
const Deleter &deleter);
65 virtual ~ByteBlob () { deleter_ (data_); }
68template<
class Deleter>
70 BlobImpl (name, dsize, data), deleter_ (deleter)
73template<
class Deleter>
String
74ByteBlob<Deleter>::string ()
76 if (string_.empty() && size_)
81 string_ =
String (data_, size_);
90 return implp_ ? implp_->name_ :
"";
93Blob::operator
bool ()
const
95 return implp_ && implp_->size_;
101 return implp_ ? implp_->data_ : NULL;
107 return reinterpret_cast<const uint8*
> (
data());
113 return implp_ ? implp_->size_ : 0;
131 if ((auto_url[0] >=
'a' && auto_url[0] <=
'z') || (auto_url[0] >=
'A' && auto_url[0] <=
'Z'))
134 while ((auto_url[i] >=
'a' && auto_url[i] <=
'z') || (auto_url[i] >=
'A' && auto_url[i] <=
'Z') ||
136 (auto_url[i] >=
'0' && auto_url[i] <=
'9'))
138 if (auto_url[i] ==
':')
142 implp_ = other.implp_;
148 implp_ = other.implp_;
155 if (lurl.
compare (0, 4,
"res:") == 0)
156 return from_res (url.
c_str() + 4);
157 if (lurl.
compare (0, 5,
"file:") == 0)
164Blob::from_string (
const String &name,
const String &data)
170string_read (
const String &filename,
const int fd,
size_t guess)
174 data.resize (guess + 1);
178 for (ssize_t l = 1; l > 0; )
180 if (stored >= data.size())
181 data.resize (2 * data.size());
183 l =
read (fd, &data[stored], data.size() - stored);
184 while (l < 0 && (errno == EAGAIN || errno == EINTR));
185 stored +=
std::max (ssize_t (0), l);
187 BDEBUG (
"%s: read: %s", filename, strerror (errno));
191 data.resize (stored);
200 const int fd =
open (filename.
c_str(), O_RDONLY | O_NOCTTY | O_CLOEXEC, 0);
201 struct stat sbuf = { 0, };
202 size_t file_size = 0;
204 return error_result (filename,
ENOENT);
205 if (
fstat (fd, &sbuf) == 0 && sbuf.st_size)
206 file_size = sbuf.st_size;
209 if (file_size >= 128 * 1024 &&
210 MAP_FAILED != (maddr =
mmap (NULL, file_size, PROT_READ, MAP_SHARED | MAP_DENYWRITE | MAP_POPULATE, fd, 0)))
213 struct MunmapDeleter {
215 explicit MunmapDeleter (
size_t l) : length (l) {}
216 void operator() (
const char *d) {
munmap ((
void*) d, length); }
222 String iodata = string_read (filename, fd, file_size);
223 const int saved_errno =
errno;
227 return from_string (filename, iodata);
229 return error_result (filename,
ENOENT);
257zintern_decompress (
unsigned int decompressed_size,
const unsigned char *cdata,
unsigned int cdata_size)
259 uLongf dlen = decompressed_size;
264 int64 result = uncompress (text, &dlen, cdata, cdata_size);
269 if (dlen == decompressed_size)
276 err =
"internal data corruption";
284 err =
"insufficient buffer size";
287 err =
"unknown error";
293 BDEBUG (
"failed to decompress (%p, %u): %s", cdata, cdata_size, err);
303 const char *
const filename_;
304 const size_t filesize_;
305 const char *
const packdata_;
306 const size_t packsize_;
310 LocalResourceEntry (
const char *filename,
size_t filesize,
const char *packdata,
size_t packsize) :
311 filename_ (filename), filesize_ (filesize), packdata_ (packdata), packsize_ (packsize), next_ (chain_)
321Blob::from_res (
const char *resource)
326 if (strcmp (resource, entry->filename_) == 0)
329 entry = entry->next_;
332 (entry->filesize_ == entry->packsize_ ||
333 entry->filesize_ + 1 == entry->packsize_))
335 if (entry->filesize_ + 1 == entry->packsize_)
340 entry->packsize_ && entry->filesize_ == 0)
341 return Blob (
std::make_shared<ByteBlob<NoDelete>> (resource, entry->packsize_, entry->packdata_, NoDelete()));
343 if (entry && entry->packsize_ < entry->filesize_)
346 const char *
data =
reinterpret_cast<const char*
> (u8data);
347 struct ZinternDeleter {
void operator() (
const char *d) { zintern_free ((uint8*) d); } };
351 return error_result (resource, ENOENT,
String (entry ?
"invalid" :
"unknown") +
" resource entry");
Binary large object storage container.
static Blob from_file(const String &filename)
Create Blob by loading from filename.
const uint8 * bytes()
Retrieve the Blob's data as uint8 buffer.
static Blob from_url(const String &url)
Create Blob by opening a url.
String name()
Retrieve the Blob's filename or url.
const char * data()
Retrieve the Blob's data.
size_t size()
Retrieve the Blob's data size in bytes.
String string()
Copy Blob data into a zero terminated string.
Blob()
Construct an empty Blob.
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
#define assert_return_unreached(...)
Return from the current function and issue an assertion warning.
#define CQUOTE(str)
Produce a const char* string, wrapping str into C-style double quotes.
The Anklang C++ API namespace.
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
String string_tolower(const String &str)
Convert all string characters into Unicode lower case characters.
uint8_t uint8
An 8-bit unsigned integer.
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
uint8 * zintern_decompress(unsigned int decompressed_size, const unsigned char *cdata, unsigned int cdata_size)
std::string String
Convenience alias for std::string.
void zintern_free(uint8 *dc_data)
Free data returned from zintern_decompress().