113d1d17dSmrg/*
213d1d17dSmrg * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
313d1d17dSmrg *
413d1d17dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
513d1d17dSmrg * copy of this software and associated documentation files (the "Software"),
613d1d17dSmrg * to deal in the Software without restriction, including without limitation
713d1d17dSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub
813d1d17dSmrg * license, and/or sell copies of the Software, and to permit persons to whom
913d1d17dSmrg * the Software is furnished to do so, subject to the following conditions:
1013d1d17dSmrg *
1113d1d17dSmrg * The above copyright notice and this permission notice (including the next
1213d1d17dSmrg * paragraph) shall be included in all copies or substantial portions of the
1313d1d17dSmrg * Software.
1413d1d17dSmrg *
1513d1d17dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1613d1d17dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1713d1d17dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1813d1d17dSmrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
1913d1d17dSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2013d1d17dSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2113d1d17dSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
2213d1d17dSmrg *
2313d1d17dSmrg * Authors:
2413d1d17dSmrg *      Jerome Glisse
2513d1d17dSmrg */
2613d1d17dSmrg#include <errno.h>
2713d1d17dSmrg#include <stdlib.h>
2813d1d17dSmrg#include <string.h>
2913d1d17dSmrg#include "bof.h"
3013d1d17dSmrg
3113d1d17dSmrg/*
3213d1d17dSmrg * helpers
3313d1d17dSmrg */
3413d1d17dSmrgstatic int bof_entry_grow(bof_t *bof)
3513d1d17dSmrg{
3613d1d17dSmrg	bof_t **array;
3713d1d17dSmrg
3813d1d17dSmrg	if (bof->array_size < bof->nentry)
3913d1d17dSmrg		return 0;
4013d1d17dSmrg	array = realloc(bof->array, (bof->nentry + 16) * sizeof(void*));
4113d1d17dSmrg	if (array == NULL)
4213d1d17dSmrg		return -ENOMEM;
4313d1d17dSmrg	bof->array = array;
4413d1d17dSmrg	bof->nentry += 16;
4513d1d17dSmrg	return 0;
4613d1d17dSmrg}
4713d1d17dSmrg
4813d1d17dSmrg/*
4913d1d17dSmrg * object
5013d1d17dSmrg */
5113d1d17dSmrgbof_t *bof_object(void)
5213d1d17dSmrg{
5313d1d17dSmrg	bof_t *object;
5413d1d17dSmrg
5513d1d17dSmrg	object = calloc(1, sizeof(bof_t));
5613d1d17dSmrg	if (object == NULL)
5713d1d17dSmrg		return NULL;
5813d1d17dSmrg	object->refcount = 1;
5913d1d17dSmrg	object->type = BOF_TYPE_OBJECT;
6013d1d17dSmrg	object->size = 12;
6113d1d17dSmrg	return object;
6213d1d17dSmrg}
6313d1d17dSmrg
6413d1d17dSmrgbof_t *bof_object_get(bof_t *object, const char *keyname)
6513d1d17dSmrg{
6613d1d17dSmrg	unsigned i;
6713d1d17dSmrg
6813d1d17dSmrg	for (i = 0; i < object->array_size; i += 2) {
6913d1d17dSmrg		if (!strcmp(object->array[i]->value, keyname)) {
7013d1d17dSmrg			return object->array[i + 1];
7113d1d17dSmrg		}
7213d1d17dSmrg	}
7313d1d17dSmrg	return NULL;
7413d1d17dSmrg}
7513d1d17dSmrg
7613d1d17dSmrgint bof_object_set(bof_t *object, const char *keyname, bof_t *value)
7713d1d17dSmrg{
7813d1d17dSmrg	bof_t *key;
7913d1d17dSmrg	int r;
8013d1d17dSmrg
8113d1d17dSmrg	if (object->type != BOF_TYPE_OBJECT)
8213d1d17dSmrg		return -EINVAL;
8313d1d17dSmrg	r = bof_entry_grow(object);
8413d1d17dSmrg	if (r)
8513d1d17dSmrg		return r;
8613d1d17dSmrg	key = bof_string(keyname);
8713d1d17dSmrg	if (key == NULL)
8813d1d17dSmrg		return -ENOMEM;
8913d1d17dSmrg	object->array[object->array_size++] = key;
9013d1d17dSmrg	object->array[object->array_size++] = value;
9113d1d17dSmrg	object->size += value->size;
9213d1d17dSmrg	object->size += key->size;
9313d1d17dSmrg	bof_incref(value);
9413d1d17dSmrg	return 0;
9513d1d17dSmrg}
9613d1d17dSmrg
9713d1d17dSmrg/*
9813d1d17dSmrg * array
9913d1d17dSmrg */
10013d1d17dSmrgbof_t *bof_array(void)
10113d1d17dSmrg{
10213d1d17dSmrg	bof_t *array = bof_object();
10313d1d17dSmrg
10413d1d17dSmrg	if (array == NULL)
10513d1d17dSmrg		return NULL;
10613d1d17dSmrg	array->type = BOF_TYPE_ARRAY;
10713d1d17dSmrg	array->size = 12;
10813d1d17dSmrg	return array;
10913d1d17dSmrg}
11013d1d17dSmrg
11113d1d17dSmrgint bof_array_append(bof_t *array, bof_t *value)
11213d1d17dSmrg{
11313d1d17dSmrg	int r;
11413d1d17dSmrg	if (array->type != BOF_TYPE_ARRAY)
11513d1d17dSmrg		return -EINVAL;
11613d1d17dSmrg	r = bof_entry_grow(array);
11713d1d17dSmrg	if (r)
11813d1d17dSmrg		return r;
11913d1d17dSmrg	array->array[array->array_size++] = value;
12013d1d17dSmrg	array->size += value->size;
12113d1d17dSmrg	bof_incref(value);
12213d1d17dSmrg	return 0;
12313d1d17dSmrg}
12413d1d17dSmrg
12513d1d17dSmrgbof_t *bof_array_get(bof_t *bof, unsigned i)
12613d1d17dSmrg{
12713d1d17dSmrg	if (!bof_is_array(bof) || i >= bof->array_size)
12813d1d17dSmrg		return NULL;
12913d1d17dSmrg	return bof->array[i];
13013d1d17dSmrg}
13113d1d17dSmrg
13213d1d17dSmrgunsigned bof_array_size(bof_t *bof)
13313d1d17dSmrg{
13413d1d17dSmrg	if (!bof_is_array(bof))
13513d1d17dSmrg		return 0;
13613d1d17dSmrg	return bof->array_size;
13713d1d17dSmrg}
13813d1d17dSmrg
13913d1d17dSmrg/*
14013d1d17dSmrg * blob
14113d1d17dSmrg */
14213d1d17dSmrgbof_t *bof_blob(unsigned size, void *value)
14313d1d17dSmrg{
14413d1d17dSmrg	bof_t *blob = bof_object();
14513d1d17dSmrg
14613d1d17dSmrg	if (blob == NULL)
14713d1d17dSmrg		return NULL;
14813d1d17dSmrg	blob->type = BOF_TYPE_BLOB;
14913d1d17dSmrg	blob->value = calloc(1, size);
15013d1d17dSmrg	if (blob->value == NULL) {
15113d1d17dSmrg		bof_decref(blob);
15213d1d17dSmrg		return NULL;
15313d1d17dSmrg	}
15413d1d17dSmrg	blob->size = size;
15513d1d17dSmrg	memcpy(blob->value, value, size);
15613d1d17dSmrg	blob->size += 12;
15713d1d17dSmrg	return blob;
15813d1d17dSmrg}
15913d1d17dSmrg
16013d1d17dSmrgunsigned bof_blob_size(bof_t *bof)
16113d1d17dSmrg{
16213d1d17dSmrg	if (!bof_is_blob(bof))
16313d1d17dSmrg		return 0;
16413d1d17dSmrg	return bof->size - 12;
16513d1d17dSmrg}
16613d1d17dSmrg
16713d1d17dSmrgvoid *bof_blob_value(bof_t *bof)
16813d1d17dSmrg{
16913d1d17dSmrg	if (!bof_is_blob(bof))
17013d1d17dSmrg		return NULL;
17113d1d17dSmrg	return bof->value;
17213d1d17dSmrg}
17313d1d17dSmrg
17413d1d17dSmrg/*
17513d1d17dSmrg * string
17613d1d17dSmrg */
17713d1d17dSmrgbof_t *bof_string(const char *value)
17813d1d17dSmrg{
17913d1d17dSmrg	bof_t *string = bof_object();
18013d1d17dSmrg
18113d1d17dSmrg	if (string == NULL)
18213d1d17dSmrg		return NULL;
18313d1d17dSmrg	string->type = BOF_TYPE_STRING;
18413d1d17dSmrg	string->size = strlen(value) + 1;
18513d1d17dSmrg	string->value = calloc(1, string->size);
18613d1d17dSmrg	if (string->value == NULL) {
18713d1d17dSmrg		bof_decref(string);
18813d1d17dSmrg		return NULL;
18913d1d17dSmrg	}
19013d1d17dSmrg	strcpy(string->value, value);
19113d1d17dSmrg	string->size += 12;
19213d1d17dSmrg	return string;
19313d1d17dSmrg}
19413d1d17dSmrg
19513d1d17dSmrg/*
19613d1d17dSmrg *  int32
19713d1d17dSmrg */
19813d1d17dSmrgbof_t *bof_int32(int32_t value)
19913d1d17dSmrg{
20013d1d17dSmrg	bof_t *int32 = bof_object();
20113d1d17dSmrg
20213d1d17dSmrg	if (int32 == NULL)
20313d1d17dSmrg		return NULL;
20413d1d17dSmrg	int32->type = BOF_TYPE_INT32;
20513d1d17dSmrg	int32->size = 4;
20613d1d17dSmrg	int32->value = calloc(1, int32->size);
20713d1d17dSmrg	if (int32->value == NULL) {
20813d1d17dSmrg		bof_decref(int32);
20913d1d17dSmrg		return NULL;
21013d1d17dSmrg	}
21113d1d17dSmrg	memcpy(int32->value, &value, 4);
21213d1d17dSmrg	int32->size += 12;
21313d1d17dSmrg	return int32;
21413d1d17dSmrg}
21513d1d17dSmrg
21613d1d17dSmrgint32_t bof_int32_value(bof_t *bof)
21713d1d17dSmrg{
21813d1d17dSmrg	return *((uint32_t*)bof->value);
21913d1d17dSmrg}
22013d1d17dSmrg
22113d1d17dSmrg/*
22213d1d17dSmrg *  common
22313d1d17dSmrg */
22413d1d17dSmrgstatic void bof_indent(int level)
22513d1d17dSmrg{
22613d1d17dSmrg	int i;
22713d1d17dSmrg
22813d1d17dSmrg	for (i = 0; i < level; i++)
22913d1d17dSmrg		fprintf(stderr, " ");
23013d1d17dSmrg}
23113d1d17dSmrg
23213d1d17dSmrgstatic void bof_print_bof(bof_t *bof, int level, int entry)
23313d1d17dSmrg{
23413d1d17dSmrg	bof_indent(level);
23513d1d17dSmrg	if (bof == NULL) {
23613d1d17dSmrg		fprintf(stderr, "--NULL-- for entry %d\n", entry);
23713d1d17dSmrg		return;
23813d1d17dSmrg	}
23913d1d17dSmrg	switch (bof->type) {
24013d1d17dSmrg	case BOF_TYPE_STRING:
24113d1d17dSmrg		fprintf(stderr, "%p string [%s %d]\n", bof, (char*)bof->value, bof->size);
24213d1d17dSmrg		break;
24313d1d17dSmrg	case BOF_TYPE_INT32:
24413d1d17dSmrg		fprintf(stderr, "%p int32 [%d %d]\n", bof, *(int*)bof->value, bof->size);
24513d1d17dSmrg		break;
24613d1d17dSmrg	case BOF_TYPE_BLOB:
24713d1d17dSmrg		fprintf(stderr, "%p blob [%d]\n", bof, bof->size);
24813d1d17dSmrg		break;
24913d1d17dSmrg	case BOF_TYPE_NULL:
25013d1d17dSmrg		fprintf(stderr, "%p null [%d]\n", bof, bof->size);
25113d1d17dSmrg		break;
25213d1d17dSmrg	case BOF_TYPE_OBJECT:
25313d1d17dSmrg		fprintf(stderr, "%p object [%d %d]\n", bof, bof->array_size / 2, bof->size);
25413d1d17dSmrg		break;
25513d1d17dSmrg	case BOF_TYPE_ARRAY:
25613d1d17dSmrg		fprintf(stderr, "%p array [%d %d]\n", bof, bof->array_size, bof->size);
25713d1d17dSmrg		break;
25813d1d17dSmrg	default:
25913d1d17dSmrg		fprintf(stderr, "%p unknown [%d]\n", bof, bof->type);
26013d1d17dSmrg		return;
26113d1d17dSmrg	}
26213d1d17dSmrg}
26313d1d17dSmrg
26413d1d17dSmrgstatic void bof_print_rec(bof_t *bof, int level, int entry)
26513d1d17dSmrg{
26613d1d17dSmrg	unsigned i;
26713d1d17dSmrg
26813d1d17dSmrg	bof_print_bof(bof, level, entry);
26913d1d17dSmrg	for (i = 0; i < bof->array_size; i++) {
27013d1d17dSmrg		bof_print_rec(bof->array[i], level + 2, i);
27113d1d17dSmrg	}
27213d1d17dSmrg}
27313d1d17dSmrg
27413d1d17dSmrgvoid bof_print(bof_t *bof)
27513d1d17dSmrg{
27613d1d17dSmrg	bof_print_rec(bof, 0, 0);
27713d1d17dSmrg}
27813d1d17dSmrg
27913d1d17dSmrgstatic int bof_read(bof_t *root, FILE *file, long end, int level)
28013d1d17dSmrg{
28113d1d17dSmrg	bof_t *bof = NULL;
28213d1d17dSmrg	int r;
28313d1d17dSmrg
28413d1d17dSmrg	if (ftell(file) >= end) {
28513d1d17dSmrg		return 0;
28613d1d17dSmrg	}
28713d1d17dSmrg	r = bof_entry_grow(root);
28813d1d17dSmrg	if (r)
28913d1d17dSmrg		return r;
29013d1d17dSmrg	bof = bof_object();
29113d1d17dSmrg	if (bof == NULL)
29213d1d17dSmrg		return -ENOMEM;
29313d1d17dSmrg	bof->offset = ftell(file);
29413d1d17dSmrg	r = fread(&bof->type, 4, 1, file);
29513d1d17dSmrg	if (r != 1)
29613d1d17dSmrg		goto out_err;
29713d1d17dSmrg	r = fread(&bof->size, 4, 1, file);
29813d1d17dSmrg	if (r != 1)
29913d1d17dSmrg		goto out_err;
30013d1d17dSmrg	r = fread(&bof->array_size, 4, 1, file);
30113d1d17dSmrg	if (r != 1)
30213d1d17dSmrg		goto out_err;
30313d1d17dSmrg	switch (bof->type) {
30413d1d17dSmrg	case BOF_TYPE_STRING:
30513d1d17dSmrg	case BOF_TYPE_INT32:
30613d1d17dSmrg	case BOF_TYPE_BLOB:
30713d1d17dSmrg		bof->value = calloc(1, bof->size - 12);
30813d1d17dSmrg		if (bof->value == NULL) {
30913d1d17dSmrg			goto out_err;
31013d1d17dSmrg		}
31113d1d17dSmrg		r = fread(bof->value, bof->size - 12, 1, file);
31213d1d17dSmrg		if (r != 1) {
31313d1d17dSmrg			fprintf(stderr, "error reading %d\n", bof->size - 12);
31413d1d17dSmrg			goto out_err;
31513d1d17dSmrg		}
31613d1d17dSmrg		break;
31713d1d17dSmrg	case BOF_TYPE_NULL:
31813d1d17dSmrg		return 0;
31913d1d17dSmrg	case BOF_TYPE_OBJECT:
32013d1d17dSmrg	case BOF_TYPE_ARRAY:
32113d1d17dSmrg		r = bof_read(bof, file, bof->offset + bof->size, level + 2);
32213d1d17dSmrg		if (r)
32313d1d17dSmrg			goto out_err;
32413d1d17dSmrg		break;
32513d1d17dSmrg	default:
32613d1d17dSmrg		fprintf(stderr, "invalid type %d\n", bof->type);
32713d1d17dSmrg		goto out_err;
32813d1d17dSmrg	}
32913d1d17dSmrg	root->array[root->centry++] = bof;
33013d1d17dSmrg	return bof_read(root, file, end, level);
33113d1d17dSmrgout_err:
33213d1d17dSmrg	bof_decref(bof);
33313d1d17dSmrg	return -EINVAL;
33413d1d17dSmrg}
33513d1d17dSmrg
33613d1d17dSmrgbof_t *bof_load_file(const char *filename)
33713d1d17dSmrg{
33813d1d17dSmrg	bof_t *root = bof_object();
33913d1d17dSmrg	int r;
34013d1d17dSmrg
34113d1d17dSmrg	if (root == NULL) {
34213d1d17dSmrg		fprintf(stderr, "%s failed to create root object\n", __func__);
34313d1d17dSmrg		return NULL;
34413d1d17dSmrg	}
34513d1d17dSmrg	root->file = fopen(filename, "r");
34613d1d17dSmrg	if (root->file == NULL)
34713d1d17dSmrg		goto out_err;
34813d1d17dSmrg	r = fseek(root->file, 0L, SEEK_SET);
34913d1d17dSmrg	if (r) {
35013d1d17dSmrg		fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename);
35113d1d17dSmrg		goto out_err;
35213d1d17dSmrg	}
35313d1d17dSmrg	root->offset = ftell(root->file);
35413d1d17dSmrg	r = fread(&root->type, 4, 1, root->file);
35513d1d17dSmrg	if (r != 1)
35613d1d17dSmrg		goto out_err;
35713d1d17dSmrg	r = fread(&root->size, 4, 1, root->file);
35813d1d17dSmrg	if (r != 1)
35913d1d17dSmrg		goto out_err;
36013d1d17dSmrg	r = fread(&root->array_size, 4, 1, root->file);
36113d1d17dSmrg	if (r != 1)
36213d1d17dSmrg		goto out_err;
36313d1d17dSmrg	r = bof_read(root, root->file, root->offset + root->size, 2);
36413d1d17dSmrg	if (r)
36513d1d17dSmrg		goto out_err;
36613d1d17dSmrg	return root;
36713d1d17dSmrgout_err:
36813d1d17dSmrg	bof_decref(root);
36913d1d17dSmrg	return NULL;
37013d1d17dSmrg}
37113d1d17dSmrg
37213d1d17dSmrgvoid bof_incref(bof_t *bof)
37313d1d17dSmrg{
37413d1d17dSmrg	bof->refcount++;
37513d1d17dSmrg}
37613d1d17dSmrg
37713d1d17dSmrgvoid bof_decref(bof_t *bof)
37813d1d17dSmrg{
37913d1d17dSmrg	unsigned i;
38013d1d17dSmrg
38113d1d17dSmrg	if (bof == NULL)
38213d1d17dSmrg		return;
38313d1d17dSmrg	if (--bof->refcount > 0)
38413d1d17dSmrg		return;
38513d1d17dSmrg	for (i = 0; i < bof->array_size; i++) {
38613d1d17dSmrg		bof_decref(bof->array[i]);
38713d1d17dSmrg		bof->array[i] = NULL;
38813d1d17dSmrg	}
38913d1d17dSmrg	bof->array_size = 0;
39013d1d17dSmrg	if (bof->file) {
39113d1d17dSmrg		fclose(bof->file);
39213d1d17dSmrg		bof->file = NULL;
39313d1d17dSmrg	}
39413d1d17dSmrg	free(bof->array);
39513d1d17dSmrg	free(bof->value);
39613d1d17dSmrg	free(bof);
39713d1d17dSmrg}
39813d1d17dSmrg
39913d1d17dSmrgstatic int bof_file_write(bof_t *bof, FILE *file)
40013d1d17dSmrg{
40113d1d17dSmrg	unsigned i;
40213d1d17dSmrg	int r;
40313d1d17dSmrg
40413d1d17dSmrg	r = fwrite(&bof->type, 4, 1, file);
40513d1d17dSmrg	if (r != 1)
40613d1d17dSmrg		return -EINVAL;
40713d1d17dSmrg	r = fwrite(&bof->size, 4, 1, file);
40813d1d17dSmrg	if (r != 1)
40913d1d17dSmrg		return -EINVAL;
41013d1d17dSmrg	r = fwrite(&bof->array_size, 4, 1, file);
41113d1d17dSmrg	if (r != 1)
41213d1d17dSmrg		return -EINVAL;
41313d1d17dSmrg	switch (bof->type) {
41413d1d17dSmrg	case BOF_TYPE_NULL:
41513d1d17dSmrg		if (bof->size)
41613d1d17dSmrg			return -EINVAL;
41713d1d17dSmrg		break;
41813d1d17dSmrg	case BOF_TYPE_STRING:
41913d1d17dSmrg	case BOF_TYPE_INT32:
42013d1d17dSmrg	case BOF_TYPE_BLOB:
42113d1d17dSmrg		r = fwrite(bof->value, bof->size - 12, 1, file);
42213d1d17dSmrg		if (r != 1)
42313d1d17dSmrg			return -EINVAL;
42413d1d17dSmrg		break;
42513d1d17dSmrg	case BOF_TYPE_OBJECT:
42613d1d17dSmrg	case BOF_TYPE_ARRAY:
42713d1d17dSmrg		for (i = 0; i < bof->array_size; i++) {
42813d1d17dSmrg			r = bof_file_write(bof->array[i], file);
42913d1d17dSmrg			if (r)
43013d1d17dSmrg				return r;
43113d1d17dSmrg		}
43213d1d17dSmrg		break;
43313d1d17dSmrg	default:
43413d1d17dSmrg		return -EINVAL;
43513d1d17dSmrg	}
43613d1d17dSmrg	return 0;
43713d1d17dSmrg}
43813d1d17dSmrg
43913d1d17dSmrgint bof_dump_file(bof_t *bof, const char *filename)
44013d1d17dSmrg{
44113d1d17dSmrg	unsigned i;
44213d1d17dSmrg	int r = 0;
44313d1d17dSmrg
44413d1d17dSmrg	if (bof->file) {
44513d1d17dSmrg		fclose(bof->file);
44613d1d17dSmrg		bof->file = NULL;
44713d1d17dSmrg	}
44813d1d17dSmrg	bof->file = fopen(filename, "w");
44913d1d17dSmrg	if (bof->file == NULL) {
45013d1d17dSmrg		fprintf(stderr, "%s failed to open file %s\n", __func__, filename);
45113d1d17dSmrg		r = -EINVAL;
45213d1d17dSmrg		goto out_err;
45313d1d17dSmrg	}
45413d1d17dSmrg	r = fseek(bof->file, 0L, SEEK_SET);
45513d1d17dSmrg	if (r) {
45613d1d17dSmrg		fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename);
45713d1d17dSmrg		goto out_err;
45813d1d17dSmrg	}
45913d1d17dSmrg	r = fwrite(&bof->type, 4, 1, bof->file);
46013d1d17dSmrg	if (r != 1)
46113d1d17dSmrg		goto out_err;
46213d1d17dSmrg	r = fwrite(&bof->size, 4, 1, bof->file);
46313d1d17dSmrg	if (r != 1)
46413d1d17dSmrg		goto out_err;
46513d1d17dSmrg	r = fwrite(&bof->array_size, 4, 1, bof->file);
46613d1d17dSmrg	if (r != 1)
46713d1d17dSmrg		goto out_err;
46813d1d17dSmrg	for (i = 0; i < bof->array_size; i++) {
46913d1d17dSmrg		r = bof_file_write(bof->array[i], bof->file);
47013d1d17dSmrg		if (r)
47113d1d17dSmrg			return r;
47213d1d17dSmrg	}
47313d1d17dSmrgout_err:
47413d1d17dSmrg	fclose(bof->file);
47513d1d17dSmrg	bof->file = NULL;
47613d1d17dSmrg	return r;
47713d1d17dSmrg}
478