summaryrefslogtreecommitdiff
path: root/gr-run-waveform/xyzzy.h
blob: 2306eabf4fd03ff99c2cc7ea12e2233f253385aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* -*- c++ -*- */
/*
 * Copyright 2004 Free Software Foundation, Inc.
 * 
 * This file is part of GNU Radio
 * 
 * GNU Radio 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, or (at your option)
 * any later version.
 * 
 * GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifndef _XYZZY_H_
#define _XYZZY_H_ 1

#include <cstdio>
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include <boost/cstdint.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>

#include <libguile.h>

using namespace std;

// - Special case filenames that start with /-xyzzy-/... and search for
//   and load them using the single file.  We'd stick "/-zyzzy-" first
//   in the default load-path.

// - Create a C read-only "port" that "reads" from the string in the file.
//   (See guile docs on creating new kinds of ports)

// - Override the default implementation of "primitive-load" and "%search-load-path"
//   to make that happen.  See load.c in the guile source code.  Figure
//   out how to get the override done before guile is fully
//   initialized.  (Guile loads ice-9/boot9.scm to start itself up.  We'd
//   need to redirect before then.)

struct header {
    char     magic[8];
    
    boost::uint32_t offset_to_directory;	// byte offset from start of file
    boost::uint32_t size_of_directory;         // bytes
    boost::uint32_t number_of_dir_entries;
    
    boost::uint32_t offset_to_strings;	// byte offset from start of file
    boost::uint32_t size_of_strings;	// bytes
};

struct directory_entry {
    boost::uint32_t offset_to_name;	 // from start of strings
    boost::uint32_t offset_to_contents;  // from start of strings
};
    
// Each string starts with a uint32_t length, followed by length bytes.
// There is no trailing \0 in the string.    
struct string_entry {
    boost::uint32_t length;
    boost::uint8_t  *base;
};

class XYZZY {
public:
    XYZZY();
    ~XYZZY();

    // Initialize with the data file produced by gen-xyzzy.
    bool init();
    bool init(const std::string &filespec);
    
    // Does a file with name 'filename' exist in magic filesystem?
    bool file_exists(const std::string &filespec);

    // Return a C port that will read the file contents
    SCM make_read_only_port(const std::string &filespec);

    /// Parse a string data structure
    static std::string read_string(boost::uint8_t *entry, size_t length);
    static std::string read_string(struct string_entry &entry);
    static std::string read_string(std::ifstream &stream);

    // Read the header of the datafile
    boost::shared_ptr<struct header> read_header(boost::uint8_t *header);
    
    boost::shared_ptr<struct directory_entry> read_dir_entry(boost::uint8_t *header);

    std::string &get_contents(const std::string &filespec) { return _contents[filespec]; };
    
private:
    std::string   _filespec;
    std::map<std::string, std::string> _contents;
};

// C linkage bindings for Guile
extern "C" {

// These are the callbacks for thw guile ports
int  xyzzy_fill_input (SCM port);
void xyzzy_write (SCM port, const void *data, size_t size);
void xyzzy_flush (SCM port);
int  xyzzy_close (SCM port);
    
// Initialize with the data file produced by gen-xyzzy.
bool xyzzy_init(const std::string &filespec);

// Does a file with name 'filename' exist in magic filesystem?
bool xyzzy_file_exists(const std::string &filespec);

// Return a C port that will read the file contents
SCM xyzzy_make_read_only_port(const std::string &filespec);
  
} // end of extern C

#endif  // _XYZZY_H_ 1