~ivantis/armagetronad/sty+ct+ivantis

« back to all changes in this revision

Viewing changes to src/tools/tResourceManager.cpp

  • Committer: ivantis
  • Date: 2008-09-09 21:33:18 UTC
  • Revision ID: ivantis@ivantis.net-20080909213318-k43y6yuq0zd6wbsa
first commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "config.h"
 
2
 
 
3
#include <errno.h>
 
4
#include <stdio.h>
 
5
#include <stdlib.h>
 
6
#include <string.h>
 
7
#include <sys/stat.h>
 
8
#include <sys/types.h>
 
9
 
 
10
#include <libxml/nanohttp.h>
 
11
 
 
12
#include "tConfiguration.h"
 
13
#include "tDirectories.h"
 
14
#include "tResourceManager.h"
 
15
#include "tString.h"
 
16
 
 
17
// server determined resource repository
 
18
tString tResourceManager::resRepoServer("http://resource.armagetronad.net/resource/");
 
19
// the nSettingItem is in gStuff.cpp
 
20
 
 
21
// client determined resource repository
 
22
tString tResourceManager::resRepoClient("http://resource.armagetronad.net/resource/");
 
23
static tSettingItem<tString> conf_res_repo("RESOURCE_REPOSITORY_CLIENT", tResourceManager::resRepoClient);
 
24
 
 
25
static int myHTTPFetch(const char *URI, const char *filename, const char *savepath)
 
26
{
 
27
    void *ctxt = NULL;
 
28
    char *buf = NULL;
 
29
    FILE* fd;
 
30
    int len, rc;
 
31
 
 
32
    con << tOutput( "$resource_downloading", URI );
 
33
    // con << "Downloading " << URI << "...\n";
 
34
 
 
35
    ctxt = xmlNanoHTTPOpen(URI, NULL);
 
36
    if (ctxt == NULL) {
 
37
        con << "ERROR: ctxt is NULL\n";
 
38
        return 1;
 
39
    }
 
40
 
 
41
    if ( (rc = xmlNanoHTTPReturnCode(ctxt)) != 200 ) {
 
42
        con << tOutput( rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc );
 
43
        return 2;
 
44
    }
 
45
 
 
46
    fd = fopen(savepath, "w");
 
47
    if (fd < 0) {
 
48
        xmlNanoHTTPClose(ctxt);
 
49
        con << tOutput( "$resource_no_write", savepath );
 
50
        return 3;
 
51
    }
 
52
 
 
53
    //xmlNanoHTTPFetchContent( ctxt, &buf, &len );
 
54
    int maxlen = 10000;
 
55
    buf = (char*)malloc(maxlen);
 
56
    while( (len = xmlNanoHTTPRead(ctxt, buf, maxlen)) > 0 ) {
 
57
        fwrite(buf, len, 1, fd);
 
58
    }
 
59
    free(buf);
 
60
 
 
61
    xmlNanoHTTPClose(ctxt);
 
62
    fclose(fd);
 
63
 
 
64
 
 
65
    con << "OK\n";
 
66
 
 
67
    return 0;
 
68
}
 
69
 
 
70
static int myFetch(const char *URIs, const char *filename, const char *savepath) {
 
71
    const char *r = URIs, *p, *n;
 
72
    char *u;
 
73
    size_t len;
 
74
    int rv = -1;
 
75
    // r = unprocessed data             p = end-of-item + 1             u = item
 
76
    // n = to-be r                              len = length of item    savepath = result filepath
 
77
 
 
78
    while (r[0] != '\0') {
 
79
        while (r[0] == ' ') ++r;                        // skip spaces at the start of the item
 
80
        (p = strchr(r, ';')) ? 0 : (p = strchr(r, '\0'));
 
81
        n = (p[0] == '\0') ? p : (p + 1);       // next item starts after the semicolon
 
82
        // NOTE: skip semicolons, *NOT* nulls
 
83
        while (p[-1] == ' ') --p;                       // skip spaces at the end of the item
 
84
        len = (size_t)(p - r);
 
85
        if (len > 0) {                                          // skip this for null-length items
 
86
            u = (char*)malloc((len + 1) * sizeof(char));
 
87
            strncpy(u, r, len);
 
88
            u[len] = '\0';                                      // u now contains the individual URI
 
89
            rv = myHTTPFetch(u, filename, savepath);    // TODO: handle other protocols?
 
90
            free(u);
 
91
            if (rv == 0) return 0;              // If successful, return the file retrieved
 
92
        }
 
93
        r = n;                                                          // move onto the next item
 
94
    }
 
95
 
 
96
    return rv;  // last error
 
97
}
 
98
 
 
99
/*
 
100
Allows for the fetching and caching of ressources available on the web,
 
101
such as maps (xml), texture (jpg, gif, bmp), sound and models.
 
102
Nota: On some forums (such as guru3.sytes.net), it is possible for the 
 
103
download link not give information about the filename or type, ie: 
 
104
http://guru3.sytes.net/download.php?id=1191. This is why the filename 
 
105
parameter is required.
 
106
Parameters:
 
107
uri: The full uri to obtain the ressource
 
108
filename: The filename to use for the local ressource
 
109
Return a file handle to the ressource
 
110
NOTE: There must be *at least* one directory level, even if it is ./
 
111
*/
 
112
tString tResourceManager::locateResource(const char *uri, const char *file) {
 
113
    tString filepath, a_uri = tString(), savepath;
 
114
    int rv;
 
115
 
 
116
    char * to_free = NULL; // string to delete later
 
117
 
 
118
    {
 
119
        char const *pos, *posb;
 
120
        char *nf;
 
121
        size_t l;
 
122
 
 
123
        // Step 1: If 'file' has an open paren, cut everything after it off
 
124
        if ( (pos = strchr(file, '(')) ) {
 
125
            l = (size_t)(pos - file);
 
126
            nf = (char*)malloc((l + 1) * sizeof(char));
 
127
            strncpy(nf, file, l);
 
128
            nf[l] = '\0';
 
129
            file = nf;
 
130
            to_free = nf;
 
131
 
 
132
            // Step 2: Extract URI, if any
 
133
            ++pos;
 
134
            if ( (posb = strchr(pos, ')')) ) {
 
135
                l = (size_t)(posb - pos);
 
136
                nf = (char*)malloc((l + 1) * sizeof(char));
 
137
                strncpy(nf, pos, l);
 
138
                nf[l] = '\0';
 
139
                a_uri << nf << ';';
 
140
                free( nf );
 
141
            }
 
142
        }
 
143
    }
 
144
    // Validate paths and determine detination savepath
 
145
    if (!file || file[0] == '\0') {
 
146
        con << tOutput( "$resource_no_filename" );
 
147
        return (tString) NULL;
 
148
    }
 
149
    if (file[0] == '/' || file[0] == '\\') {
 
150
        con << tOutput( "$resource_abs_path" );
 
151
        return (tString) NULL;
 
152
    }
 
153
    savepath = tDirectories::Resource().GetWritePath(file);
 
154
    if (savepath == "") {
 
155
        con << tOutput( "$resource_no_writepath" );
 
156
        return (tString) NULL;
 
157
    }
 
158
 
 
159
    // Do we have this file locally ?
 
160
    filepath = tDirectories::Resource().GetReadPath(file);
 
161
 
 
162
    if (filepath != "")
 
163
    {
 
164
        if ( NULL != to_free )
 
165
            free( to_free );
 
166
        return filepath;
 
167
    }
 
168
 
 
169
    // Some sort of File not found
 
170
    if (uri && strcmp("0", uri))
 
171
        a_uri << uri << ';';
 
172
 
 
173
    // add repositories to uri
 
174
    if ( resRepoServer.Len() > 2 )
 
175
        a_uri << resRepoServer << file << ';';
 
176
 
 
177
    if ( resRepoClient.Len() > 2 && resRepoClient != resRepoServer )
 
178
        a_uri << resRepoClient << file << ';';
 
179
 
 
180
    con << tOutput( "$resource_not_cached", file );
 
181
 
 
182
    rv = myFetch((const char *)a_uri, file, (const char *)savepath);
 
183
 
 
184
    if ( NULL != to_free )
 
185
        free( to_free );
 
186
 
 
187
    if (rv)
 
188
        return (tString) NULL;
 
189
    return savepath;
 
190
}
 
191
 
 
192
FILE* tResourceManager::openResource(const char *uri, const char *file) {
 
193
    tString filepath;
 
194
    filepath = locateResource(uri, file);
 
195
    if ( filepath.Len() <= 1 )
 
196
        return NULL;
 
197
    return fopen((const char *)filepath, "r");
 
198
}
 
199
 
 
200
static void RInclude(std::istream& s)
 
201
{
 
202
    tString file;
 
203
    s >> file;
 
204
 
 
205
    tString rclcl = tResourceManager::locateResource(NULL, file);
 
206
    if ( rclcl ) {
 
207
        std::ifstream rc(rclcl);
 
208
        tConfItemBase::LoadAll(rc, false );
 
209
        return;
 
210
    }
 
211
 
 
212
    con << tOutput( "$config_rinclude_not_found", file );
 
213
}
 
214
 
 
215
static tConfItemFunc s_RInclude("RINCLUDE",  &RInclude);
 
216