Some updated to bundle/settings to integrate the two. Settings can now be seamlessly loaded from bundle/share/settings directory. This is useful to opentv module but may be useful elsewhere in the future.

This commit is contained in:
Adam Sutton 2012-08-03 12:30:32 +01:00
parent d1e94d8a46
commit a8096d4ea8
12 changed files with 432 additions and 488 deletions

View file

@ -169,7 +169,7 @@ CFLAGS_com = -g -funsigned-char -O2
CFLAGS_com += -D_FILE_OFFSET_BITS=64
CFLAGS_com += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR}
MKBUNDLE = $(CURDIR)/support/mkbundle.py
MKBUNDLE = $(CURDIR)/support/mkbundle
ifndef V
ECHO = printf "$(1)\t\t%s\n" $(2)

View file

@ -32,13 +32,6 @@
* Opaque data types
* *************************************************************************/
/* Bundle or Direct */
typedef enum filebundle_handle_type
{
FB_BUNDLE,
FB_DIRECT
} fb_type;
/* File bundle dir handle */
typedef struct filebundle_dir
{
@ -142,6 +135,42 @@ static uint8_t *_fb_deflate ( const uint8_t *data, size_t orig, size_t *size )
return bufout;
}
/* **************************************************************************
* Miscellanous
* *************************************************************************/
/* Get path stats */
// TODO: this could do with being more efficient
int fb_stat ( const char *path, struct filebundle_stat *st )
{
int ret = 1;
fb_dir *dir;
fb_file *fp;
if (*path == '/') {
struct stat _st;
if (!lstat(path, &_st)) {
st->type = FB_DIRECT;
st->is_dir = S_ISDIR(_st.st_mode) ? 1 : 0;
st->size = _st.st_size;
ret = 0;
}
} else if ((dir = fb_opendir(path))) {
st->type = dir->type;
st->is_dir = 1;
st->size = 0;
ret = 0;
fb_closedir(dir);
} else if ((fp = fb_open(path, 0, 0))) {
st->type = fp->type;
st->is_dir = 0;
st->size = fp->size;
ret = 0;
fb_close(fp);
}
return ret;
}
/* **************************************************************************
* Directory processing
* *************************************************************************/
@ -213,7 +242,7 @@ fb_dirent *fb_readdir ( fb_dir *dir )
fb_dirent *ret = NULL;
if (dir->type == FB_BUNDLE) {
if (dir->b.cur) {
dir->dirent.name = dir->b.cur->name;
strcpy(dir->dirent.name, dir->b.cur->name);
dir->dirent.type = dir->b.cur->type;
dir->b.cur = dir->b.cur->next;
ret = &dir->dirent;
@ -225,7 +254,7 @@ fb_dirent *fb_readdir ( fb_dir *dir )
struct stat st;
char buf[512];
snprintf(buf, sizeof(buf), "%s/%s", dir->d.root, de->d_name);
dir->dirent.name = de->d_name;
strcpy(dir->dirent.name, de->d_name);
dir->dirent.type = FB_UNKNOWN;
if (!lstat(buf, &st))
dir->dirent.type = S_ISDIR(st.st_mode) ? FB_DIR : FB_FILE;
@ -235,6 +264,50 @@ fb_dirent *fb_readdir ( fb_dir *dir )
return ret;
}
/* Get entry list */
int fb_scandir ( const char *path, fb_dirent ***list )
{
int i, ret = -1;
struct dirent **de;
struct filebundle_stat st;
if (fb_stat(path, &st)) return -1;
if (!st.is_dir) return -1;
/* Direct */
if (st.type == FB_DIRECT) {
if ((ret = scandir(path, &de, NULL, NULL)) != -1) {
if (ret == 0) return 0;
*list = malloc(sizeof(fb_dirent*)*ret);
for (i = 0; i < ret; i++) {
(*list)[i] = calloc(1, sizeof(fb_dirent));
strcpy((*list)[i]->name, de[i]->d_name);
(*list)[i]->type = FB_DIRECT;
free(de[i]);
}
free(de);
}
/* Bundle */
} else {
fb_dir *dir;
if ((dir = fb_opendir(path))) {
const filebundle_entry_t *fb;
ret = dir->b.root->d.count;
fb = dir->b.root->d.child;
*list = malloc(ret * sizeof(fb_dirent));
i = 0;
while (fb) {
(*list)[i] = calloc(1, sizeof(fb_dirent));
strcpy((*list)[i]->name, fb->name);
fb = fb->next;
i++;
}
fb_closedir(dir);
}
}
return ret;
}
/* **************************************************************************
* Directory processing
* *************************************************************************/
@ -344,6 +417,7 @@ fb_file *fb_open ( const char *path, int decompress, int compress )
/* Open */
ret = fb_open2(dir, pos+1, decompress, compress);
fb_closedir(dir);
free(tmp);
return ret;
}
@ -351,8 +425,9 @@ fb_file *fb_open ( const char *path, int decompress, int compress )
/* Close file */
void fb_close ( fb_file *fp )
{
if (fp->type == FB_DIRECT && fp->d.cur)
if (fp->type == FB_DIRECT && fp->d.cur) {
fclose(fp->d.cur);
}
if (fp->buf)
free(fp->buf);
free(fp);
@ -387,7 +462,6 @@ ssize_t fb_read ( fb_file *fp, void *buf, size_t count )
fp->pos += count;
} else if (fp->type == FB_DIRECT) {
fp->pos += fread(buf, 1, count, fp->d.cur);
return -1;
} else {
count = MIN(count, fp->b.root->f.size - fp->pos);
memcpy(buf, fp->b.root->f.data + fp->pos, count);

View file

@ -24,6 +24,13 @@
#include <dirent.h>
#include <stdio.h>
/* Bundle or Direct */
typedef enum filebundle_handle_type
{
FB_BUNDLE,
FB_DIRECT
} fb_type;
/* File bundle entry type */
enum filebundle_type
{
@ -39,6 +46,7 @@ typedef struct filebundle_entry
const char *name;
union {
struct {
size_t count;
struct filebundle_entry *child;
} d;
struct {
@ -53,10 +61,18 @@ typedef struct filebundle_entry
/* File bundle directory entry */
typedef struct filebundle_dirent
{
const char *name;
enum filebundle_type type;
char name[256];
enum filebundle_type type;
} fb_dirent;
/* File bundle stat */
struct filebundle_stat
{
fb_type type;
uint8_t is_dir;
size_t size;
};
/* Opaque types */
typedef struct filebundle_dir fb_dir;
typedef struct filebundle_file fb_file;
@ -64,10 +80,14 @@ typedef struct filebundle_file fb_file;
/* Root of bundle */
extern filebundle_entry_t *filebundle_root;
/* Miscellaneous */
int fb_stat ( const char *path, struct filebundle_stat *st );
/* Directory processing wrappers */
fb_dir *fb_opendir ( const char *path );
fb_dirent *fb_readdir ( fb_dir *fb );
void fb_closedir ( fb_dir *fb );
int fb_scandir ( const char *path, fb_dirent ***list );
/* File processing wrappers */
// Note: all access is read-only

View file

@ -31,6 +31,7 @@
#include "htsmsg_json.h"
#include "settings.h"
#include "tvheadend.h"
#include "filebundle.h"
static char *settingspath;
@ -43,7 +44,6 @@ hts_settings_get_root(void)
return settingspath ?: "No settings dir";
}
/**
*
*/
@ -56,17 +56,12 @@ hts_settings_init(const char *confpath)
if(confpath != NULL) {
settingspath = strdup(confpath);
} else {
if(homedir != NULL) {
snprintf(buf, sizeof(buf), "%s/.hts", homedir);
if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0) {
snprintf(buf, sizeof(buf), "%s/.hts/tvheadend", homedir);
if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0)
settingspath = strdup(buf);
}
} else if(homedir != NULL) {
snprintf(buf, sizeof(buf), "%s/.hts", homedir);
if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0) {
snprintf(buf, sizeof(buf), "%s/.hts/tvheadend", homedir);
if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0)
settingspath = strdup(buf);
}
}
if(settingspath == NULL) {
@ -82,139 +77,42 @@ hts_settings_init(const char *confpath)
}
}
/**
*
*/
void
hts_settings_save(htsmsg_t *record, const char *pathfmt, ...)
{
char path[256];
char fullpath[256];
char fullpath2[256];
int x, l, fd;
va_list ap;
struct stat st;
htsbuf_queue_t hq;
htsbuf_data_t *hd;
char *n;
int ok;
if(settingspath == NULL)
return;
va_start(ap, pathfmt);
vsnprintf(path, sizeof(path), pathfmt, ap);
va_end(ap);
n = path;
while(*n) {
if(*n == ':' || *n == '?' || *n == '*' || *n > 127 || *n < 32)
*n = '_';
n++;
}
l = strlen(path);
for(x = 0; x < l; x++) {
if(path[x] == '/') {
/* It's a directory here */
path[x] = 0;
snprintf(fullpath, sizeof(fullpath), "%s/%s", settingspath, path);
if(stat(fullpath, &st) && mkdir(fullpath, 0700)) {
tvhlog(LOG_ALERT, "settings", "Unable to create dir \"%s\": %s",
fullpath, strerror(errno));
return;
}
path[x] = '/';
}
}
snprintf(fullpath, sizeof(fullpath), "%s/%s.tmp", settingspath, path);
if((fd = tvh_open(fullpath, O_CREAT | O_TRUNC | O_RDWR, 0700)) < 0) {
tvhlog(LOG_ALERT, "settings", "Unable to create \"%s\" - %s",
fullpath, strerror(errno));
return;
}
ok = 1;
htsbuf_queue_init(&hq, 0);
htsmsg_json_serialize(record, &hq, 1);
TAILQ_FOREACH(hd, &hq.hq_q, hd_link)
if(write(fd, hd->hd_data + hd->hd_data_off, hd->hd_data_len) !=
hd->hd_data_len) {
tvhlog(LOG_ALERT, "settings", "Failed to write file \"%s\" - %s",
fullpath, strerror(errno));
ok = 0;
break;
}
close(fd);
snprintf(fullpath2, sizeof(fullpath2), "%s/%s", settingspath, path);
if(ok)
rename(fullpath, fullpath2);
else
unlink(fullpath);
htsbuf_queue_flush(&hq);
}
/**
*
*/
static htsmsg_t *
hts_settings_load_one(const char *filename)
{
struct stat st;
int fd;
char *mem;
htsmsg_t *r;
int n;
if(stat(filename, &st) < 0)
return NULL;
if((fd = tvh_open(filename, O_RDONLY, 0)) < 0)
return NULL;
mem = malloc(st.st_size + 1);
mem[st.st_size] = 0;
n = read(fd, mem, st.st_size);
close(fd);
if(n == st.st_size)
r = htsmsg_json_deserialize(mem);
else
r = NULL;
free(mem);
return r;
}
/**
*
*/
static int
hts_settings_buildpath(char *dst, size_t dstsize, const char *fmt, va_list ap)
hts_settings_makedirs ( char *path )
{
size_t x;
struct stat st;
size_t l = strlen(path);
for(x = 0; x < l; x++) {
if(path[x] == '/' && x != 0) {
path[x] = 0;
if(stat(path, &st) && mkdir(path, 0700)) {
tvhlog(LOG_ALERT, "settings", "Unable to create dir \"%s\": %s",
path, strerror(errno));
return -1;
}
path[x] = '/';
}
}
return 0;
}
/**
*
*/
static void
hts_settings_buildpath
(char *dst, size_t dstsize, const char *fmt, va_list ap, const char *prefix)
{
char tmp[256];
char *n = dst;
if(settingspath == NULL)
return -1;
vsnprintf(tmp, sizeof(tmp), fmt, ap);
if (*tmp != '/')
snprintf(dst, dstsize, "%s/%s", settingspath, tmp);
if (*tmp != '/' && prefix)
snprintf(dst, dstsize, "%s/%s", prefix, tmp);
else
strncpy(dst, tmp, dstsize);
@ -223,7 +121,134 @@ hts_settings_buildpath(char *dst, size_t dstsize, const char *fmt, va_list ap)
*n = '_';
n++;
}
return 0;
}
/**
*
*/
void
hts_settings_save(htsmsg_t *record, const char *pathfmt, ...)
{
char path[256];
char tmppath[256];
int fd;
va_list ap;
htsbuf_queue_t hq;
htsbuf_data_t *hd;
int ok;
if(settingspath == NULL)
return;
/* Clean the path */
va_start(ap, pathfmt);
hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
va_end(ap);
/* Create directories */
if (hts_settings_makedirs(path)) return;
/* Create tmp file */
snprintf(tmppath, sizeof(tmppath), "%s.tmp", path);
if((fd = tvh_open(tmppath, O_CREAT | O_TRUNC | O_RDWR, 0700)) < 0) {
tvhlog(LOG_ALERT, "settings", "Unable to create \"%s\" - %s",
tmppath, strerror(errno));
return;
}
/* Store data */
ok = 1;
htsbuf_queue_init(&hq, 0);
htsmsg_json_serialize(record, &hq, 1);
TAILQ_FOREACH(hd, &hq.hq_q, hd_link)
if(write(fd, hd->hd_data + hd->hd_data_off, hd->hd_data_len) !=
hd->hd_data_len) {
tvhlog(LOG_ALERT, "settings", "Failed to write file \"%s\" - %s",
tmppath, strerror(errno));
ok = 0;
break;
}
close(fd);
htsbuf_queue_flush(&hq);
/* Move */
if(ok) {
rename(tmppath, path);
/* Delete tmp */
} else
unlink(tmppath);
}
/**
*
*/
static htsmsg_t *
hts_settings_load_one(const char *filename)
{
ssize_t n;
char *mem;
fb_file *fp;
htsmsg_t *r = NULL;
/* Open */
if (!(fp = fb_open(filename, 1, 0))) return NULL;
/* Load data */
mem = malloc(fb_size(fp)+1);
n = fb_read(fp, mem, fb_size(fp));
if (n >= 0) mem[n] = 0;
fb_close(fp);
/* Decode */
if(n == fb_size(fp))
r = htsmsg_json_deserialize(mem);
free(mem);
return r;
}
/**
*
*/
static htsmsg_t *
_hts_settings_load(const char *fullpath)
{
char child[256];
struct filebundle_stat st;
fb_dirent **namelist, *d;
htsmsg_t *r, *c;
int n, i;
/* Invalid */
if (fb_stat(fullpath, &st)) return NULL;
/* Directory */
if (st.is_dir) {
/* Get file list */
if((n = fb_scandir(fullpath, &namelist)) < 0)
return NULL;
/* Read files */
r = htsmsg_create_map();
for(i = 0; i < n; i++) {
d = namelist[i];
if(d->name[0] != '.') {
snprintf(child, sizeof(child), "%s/%s", fullpath, d->name);
if ((c = hts_settings_load_one(child)))
htsmsg_add_msg(r, d->name, c);
}
free(d);
}
free(namelist);
/* File */
} else {
r = hts_settings_load_one(fullpath);
}
return r;
}
/**
@ -232,45 +257,27 @@ hts_settings_buildpath(char *dst, size_t dstsize, const char *fmt, va_list ap)
htsmsg_t *
hts_settings_load(const char *pathfmt, ...)
{
htsmsg_t *ret = NULL;
char fullpath[256];
char child[256];
va_list ap;
struct stat st;
struct dirent **namelist, *d;
htsmsg_t *r, *c;
int n, i;
/* Try normal path */
va_start(ap, pathfmt);
if(hts_settings_buildpath(fullpath, sizeof(fullpath), pathfmt, ap) < 0)
return NULL;
hts_settings_buildpath(fullpath, sizeof(fullpath),
pathfmt, ap, settingspath);
va_end(ap);
ret = _hts_settings_load(fullpath);
if(stat(fullpath, &st) != 0)
return NULL;
if(S_ISDIR(st.st_mode)) {
if((n = scandir(fullpath, &namelist, NULL, NULL)) < 0)
return NULL;
r = htsmsg_create_map();
for(i = 0; i < n; i++) {
d = namelist[i];
if(d->d_name[0] != '.') {
snprintf(child, sizeof(child), "%s/%s", fullpath, d->d_name);
c = hts_settings_load_one(child);
if(c != NULL)
htsmsg_add_msg(r, d->d_name, c);
}
free(d);
}
free(namelist);
} else {
r = hts_settings_load_one(fullpath);
/* Try bundle path */
if (!ret && *pathfmt != '/') {
va_start(ap, pathfmt);
hts_settings_buildpath(fullpath, sizeof(fullpath),
pathfmt, ap, "data/conf");
va_end(ap);
ret = _hts_settings_load(fullpath);
}
return r;
return ret;
}
/**
@ -283,12 +290,12 @@ hts_settings_remove(const char *pathfmt, ...)
va_list ap;
va_start(ap, pathfmt);
if(hts_settings_buildpath(fullpath, sizeof(fullpath), pathfmt, ap) < 0)
return;
hts_settings_buildpath(fullpath, sizeof(fullpath),
pathfmt, ap, settingspath);
va_end(ap);
unlink(fullpath);
}
/**
*
*/
@ -296,48 +303,19 @@ int
hts_settings_open_file(int for_write, const char *pathfmt, ...)
{
char path[256];
char fullpath[256];
int x, l;
va_list ap;
struct stat st;
char *n;
if(settingspath == NULL)
return -1;
/* Build path */
va_start(ap, pathfmt);
vsnprintf(path, sizeof(path), pathfmt, ap);
hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
va_end(ap);
n = path;
while(*n) {
if(*n == ':' || *n == '?' || *n == '*' || *n > 127 || *n < 32)
*n = '_';
n++;
}
l = strlen(path);
for(x = 0; x < l; x++) {
if(path[x] == '/') {
/* It's a directory here */
path[x] = 0;
snprintf(fullpath, sizeof(fullpath), "%s/%s", settingspath, path);
if(stat(fullpath, &st) && mkdir(fullpath, 0700)) {
tvhlog(LOG_ALERT, "settings", "Unable to create dir \"%s\": %s",
fullpath, strerror(errno));
return -1;
}
path[x] = '/';
}
}
snprintf(fullpath, sizeof(fullpath), "%s/%s", settingspath, path);
/* Create directories */
if (for_write)
if (hts_settings_makedirs(path)) return -1;
/* Open file */
int flags = for_write ? O_CREAT | O_TRUNC | O_WRONLY : O_RDONLY;
return tvh_open(fullpath, flags, 0700);
return tvh_open(path, flags, 0700);
}

View file

@ -1,133 +1,155 @@
#!/bin/bash
#!/usr/bin/env python
#
# Filebundle generator
# Copyright (C) 2009 Andreas Öman
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Replacement for old mkbundle script that creates a full file heirarchy
#
set -u # Fail on undefined vars
import os, sys, re
import gzip, cStringIO
from optparse import OptionParser
READER="cat"
SOURCE=
DEPFILE=
OUTPUT=
PREFIX=
COMPRESS=false
usage()
{
cat << EOF
usage: $0 options
# Add reverse path split
def rsplit ( p ):
i = p.find(os.path.sep)
if i != -1:
return (p[:i], p[i+1:])
else:
return (p, '')
Generate a filebundle .c-file from a directory
# Process command line
optp = OptionParser()
optp.add_option('-z', '--gzip', action='store_true',
help='Compress the files with gzip')
optp.add_option('-l', '--gzlevel', type='int', default=9,
help='Specify compression level if using gzip')
optp.add_option('-o', '--output', default=None,
help='Specify output file (default /dev/stdout)')
optp.add_option('-d', '--deps', default=None,
help='Specify deps file to update during run')
(opts, args) = optp.parse_args()
OPTIONS:
-h Show this message
-s Source path
-d Dependency file (for use with make)
-o Output file (.c file)
-z Compress individual files using gzip
-p Filebundle prefix
EOF
}
# Setup
outf = sys.stdout
if opts.output:
outf = open(opts.output, 'w')
depf = None
if opts.deps:
depf = open(opts.deps, 'w')
print >>depf, '%s: \\' % opts.output
# Build heirarchy
root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..'))
ents = {}
for path in args:
for (p, ds, fs) in os.walk(path):
p = os.path.abspath(p)
n = p.replace(root+'/', '')
t = ents
while True:
(d,n) = rsplit(n)
if d not in t:
t[d] = {}
t = t[d]
if not n: break
for f in fs:
t[f] = None
while getopts "s:d:o:zhp:" OPTION
do
case $OPTION in
h)
usage
exit 1
;;
z)
READER="gzip -9"
COMPRESS=true
;;
d)
DEPFILE="$OPTARG"
;;
s)
SOURCE="$OPTARG"
;;
o)
OUTPUT="$OPTARG"
;;
p)
PREFIX="$OPTARG"
;;
esac
done
# Output a file
def output_file ( path, name, idx, next = -1 ):
n = 'NULL'
if next >= 0: n = '&filebundle_entry_%06d' % next
p = os.path.join(root, path, name);
# Dep file
if depf: print >>depf, ' %s\\' % p
if [[ -z $SOURCE ]] || [[ -z $OUTPUT ]] || [[ -z $PREFIX ]]; then
usage
exit 1
fi
# First the data
print >>outf, '// FILE : %s %s %d %d' % (path, name, idx, next)
print >>outf, 'static const uint8_t filebundle_data_%06d[] = {' % idx,
o = -1
d = open(p, 'rb').read()
if opts.gzip:
o = len(d)
l = opts.gzlevel
t = cStringIO.StringIO()
if l < 0: l = 1
if l > 9: l = 9
z = gzip.GzipFile(filename=name, mode='w', compresslevel=l, fileobj=t)
z.write(d)
z.close()
d = t.getvalue()
t.close()
i = 0
for b in d:
if not (i % 12): print >>outf, '\n ',
print >>outf, '0x%02x,' % ord(b),
i = i + 1
print >>outf, ''
print >>outf, '};'
print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
print >>outf, ' .type = FB_FILE,'
print >>outf, ' .name = "%s",' % name
print >>outf, ' .next = %s,' % n
print >>outf, ' .f.size = %d,' % len(d)
print >>outf, ' .f.orig = %d,' % o
print >>outf, ' .f.data = filebundle_data_%06d,' % idx
print >>outf, '};'
print >>outf, ''
FILES=`find "${SOURCE}" \( \( -name .svn -or -name *~ \) -and -prune \) -or -printf "%P "`
# Output a directory
def output_dir ( path, name, idx, child, count, next = -1 ):
n = 'NULL'
if next >= 0: n = '&filebundle_entry_%06d' % next
print >>outf, '// DIR: %s %s %d %d %d %d'\
% (path, name, idx, child, count, next)
print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
print >>outf, ' .type = FB_DIR,'
print >>outf, ' .name = "%s",' % name
print >>outf, ' .next = %s,' % n
print >>outf, ' .d.count = %d,' % count
print >>outf, ' .d.child = &filebundle_entry_%06d,' % child
print >>outf, '};'
print >>outf, ''
echo >${OUTPUT} "// auto-generated by $0"
# Create output
def add_entry ( ents, path = "", name = "", idx = -1, next = -1 ):
for file in $FILES; do
# Add children
d = os.path.join(path, name)
p = -1
c = 0
for k in ents:
# File
if not ents[k]:
output_file(d, k, idx+1, p)
p = idx = idx + 1
c = c + 1
# Directory
else:
tmp = add_entry(ents[k], d, k, idx, p)
if tmp != idx:
p = idx = tmp
c = c + 1
if [ -f ${SOURCE}/$file ]; then
# Add directory
if p >= 0:
if name:
output_dir(path, name, idx+1, p, c, next)
idx = idx + 1
name=`echo $file | perl -pe s#[^a-z0-9A-Z]#_#g`
echo >>${OUTPUT} "// ${SOURCE}/$file"
echo >>${OUTPUT} "static const unsigned char embedded_$name[]={"
$READER <${SOURCE}/$file | od -v -An -b | sed s/^\ */0/ | sed s/\ *$$/,/| sed s/\ /,\ 0/g|sed s/$/,/ >>${OUTPUT}
echo >>${OUTPUT} "};"
fi
done
return idx
echo >>${OUTPUT} "#include <filebundle.h>"
echo >>${OUTPUT} "static const struct filebundle_entry filebundle_entries[] = {"
[[ -z $DEPFILE ]] || echo >${DEPFILE} -n "${OUTPUT}: "
# Output header
print >>outf, '// Auto-generated - DO NOT EDIT'
print >>outf, '// COMMAND: [%s]' % (' '.join(sys.argv))
print >>outf, ''
print >>outf, '#include "filebundle.h"'
print >>outf, ''
for file in $FILES; do
[[ -z $DEPFILE ]] || echo >>${DEPFILE} -n "${SOURCE}/$file "
# Output entries
idx = add_entry(ents)
if [ -f ${SOURCE}/$file ]; then
if $COMPRESS; then
ORIGINAL_SIZE=`stat -c "%s" ${SOURCE}/$file`
else
ORIGINAL_SIZE="-1"
fi
N=`echo $file | perl -pe s#[^a-z0-9A-Z]#_#g`
echo >>${OUTPUT} "{\"$file\", embedded_$N, sizeof(embedded_$N),${ORIGINAL_SIZE}},"
fi
done
echo >>${OUTPUT} "{(void *)0, 0, 0, 0}};"
[[ -z $DEPFILE ]] || echo >>${DEPFILE} ""
cat >>${OUTPUT} <<EOF
static struct filebundle fb = {
.entries = &filebundle_entries[0],
.prefix = "${PREFIX}"
};
static void __attribute__((constructor)) filebundle_init(void)
{
extern struct filebundle *filebundles;
fb.next = filebundles;
filebundles = &fb;
}
EOF
# Output top link
print >>outf, 'filebundle_entry_t *filebundle_root = &filebundle_entry_%06d;' % idx

View file

@ -1,150 +0,0 @@
#!/usr/bin/env python
#
# Replacement for old mkbundle script that creates a full file heirarchy
#
import os, sys, re
import gzip, cStringIO
from optparse import OptionParser
# Add reverse path split
def rsplit ( p ):
i = p.find(os.path.sep)
if i != -1:
return (p[:i], p[i+1:])
else:
return (p, '')
# Process command line
optp = OptionParser()
optp.add_option('-z', '--gzip', action='store_true',
help='Compress the files with gzip')
optp.add_option('-l', '--gzlevel', type='int', default=9,
help='Specify compression level if using gzip')
optp.add_option('-o', '--output', default=None,
help='Specify output file (default /dev/stdout)')
optp.add_option('-d', '--deps', default=None,
help='Specify deps file to update during run')
(opts, args) = optp.parse_args()
# Setup
outf = sys.stdout
if opts.output:
outf = open(opts.output, 'w')
depf = None
if opts.deps:
depf = open(opts.deps, 'w')
print >>depf, '%s: \\' % opts.output
# Build heirarchy
root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..'))
ents = {}
for path in args:
for (p, ds, fs) in os.walk(path):
p = os.path.abspath(p)
n = p.replace(root+'/', '')
t = ents
while True:
(d,n) = rsplit(n)
if d not in t:
t[d] = {}
t = t[d]
if not n: break
for f in fs:
t[f] = None
# Output a file
def output_file ( path, name, idx, next = -1 ):
n = 'NULL'
if next >= 0: n = '&filebundle_entry_%06d' % next
p = os.path.join(root, path, name);
# Dep file
if depf: print >>depf, ' %s\\' % p
# First the data
print >>outf, '// FILE : %s %s %d %d' % (path, name, idx, next)
print >>outf, 'static const uint8_t filebundle_data_%06d[] = {' % idx,
o = -1
d = open(p, 'rb').read()
if opts.gzip:
o = len(d)
l = opts.gzlevel
t = cStringIO.StringIO()
if l < 0: l = 1
if l > 9: l = 9
z = gzip.GzipFile(filename=name, mode='w', compresslevel=l, fileobj=t)
z.write(d)
z.close()
d = t.getvalue()
t.close()
i = 0
for b in d:
if not (i % 12): print >>outf, '\n ',
print >>outf, '0x%02x,' % ord(b),
i = i + 1
print >>outf, ''
print >>outf, '};'
print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
print >>outf, ' .type = FB_FILE,'
print >>outf, ' .name = "%s",' % name
print >>outf, ' .next = %s,' % n
print >>outf, ' .f.size = %d,' % len(d)
print >>outf, ' .f.orig = %d,' % o
print >>outf, ' .f.data = filebundle_data_%06d,' % idx
print >>outf, '};'
print >>outf, ''
# Output a directory
def output_dir ( path, name, idx, child, next = -1 ):
n = 'NULL'
if next >= 0: n = '&filebundle_entry_%06d' % next
print >>outf, '// DIR: %s %s %d %d %d' % (path, name, idx, child, next)
print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
print >>outf, ' .type = FB_DIR,'
print >>outf, ' .name = "%s",' % name
print >>outf, ' .next = %s,' % n
print >>outf, ' .d.child = &filebundle_entry_%06d,' % child
print >>outf, '};'
print >>outf, ''
# Create output
def add_entry ( ents, path = "", name = "", idx = -1, next = -1 ):
# Add children
d = os.path.join(path, name)
p = -1
for k in ents:
# File
if not ents[k]:
output_file(d, k, idx+1, p)
p = idx = idx + 1
# Directory
else:
tmp = add_entry(ents[k], d, k, idx, p)
if tmp != idx:
p = idx = tmp
# Add directory
if p >= 0:
if name:
output_dir(path, name, idx+1, p, next)
idx = idx + 1
return idx
# Output header
print >>outf, '// Auto-generated - DO NOT EDIT'
print >>outf, '// COMMAND: [%s]' % (' '.join(sys.argv))
print >>outf, ''
print >>outf, '#include "filebundle.h"'
print >>outf, ''
# Output entries
idx = add_entry(ents)
# Output top link
print >>outf, 'filebundle_entry_t *filebundle_root = &filebundle_entry_%06d;' % idx