1 /*
2     corfiles.c:
3 
4     Copyright (C) 2011 John ffitch
5 
6     This file is part of Csound.
7 
8     The Csound Library is free software; you can redistribute it
9     and/or modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2.1 of the License, or (at your option) any later version.
12 
13     Csound is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with Csound; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21     02110-1301 USA
22 */
23 
24 #include "csoundCore.h"     /*                              CORFILES.C      */
25 #include <string.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <stdlib.h>
29 
30 
31 extern int csoundFileClose(CSOUND*, void*);
32 CORFIL *copy_url_corefile(CSOUND *, const char *, int);
33 
corfile_create_w(CSOUND * csound)34 CORFIL *corfile_create_w(CSOUND *csound)
35 {
36     CORFIL *ans = (CORFIL*) csound->Malloc(csound, sizeof(CORFIL));
37     ans->body = (char*)csound->Calloc(csound,100); /* 100 is just a number */
38     ans->len = 100;
39     ans->p = 0;
40     return ans;
41 }
42 
corfile_create_r(CSOUND * csound,const char * text)43 CORFIL *corfile_create_r(CSOUND *csound, const char *text)
44 {
45     //char *strdup(const char *);
46     CORFIL *ans = (CORFIL*) csound->Malloc(csound, sizeof(CORFIL));
47     ans->body = cs_strdup(csound, (char*)text);
48     ans->len = strlen(text)+1;
49     ans->p = 0;
50     return ans;
51 }
52 
corfile_putc(CSOUND * csound,int c,CORFIL * f)53 void corfile_putc(CSOUND *csound, int c, CORFIL *f)
54 {
55     f->body[f->p++] = c;
56     if (UNLIKELY(f->p >= f->len)) {
57       char *new = (char*) csound->ReAlloc(csound, f->body, f->len+=100);
58       if (UNLIKELY(new==NULL)) {
59         fprintf(stderr, Str("Out of Memory\n"));
60         exit(7);
61       }
62       f->body = new;
63     }
64     f->body[f->p] = '\0';
65 }
66 
corfile_puts(CSOUND * csound,const char * s,CORFIL * f)67 void corfile_puts(CSOUND *csound, const char *s, CORFIL *f)
68 {
69     const char *c;
70     int n;
71     /* skip and count the NUL chars to the end */
72     for (n=0; f->p > 0 && f->body[f->p-1] == '\0'; n++, f->p--);
73     /* append the string */
74     for (c = s; *c != '\0'; c++) {
75       f->body[f->p++] = *c;
76       if (UNLIKELY(f->p >= f->len)) {
77         char *new = (char*) csound->ReAlloc(csound, f->body, f->len+=100);
78         if (UNLIKELY(new==NULL)) {
79           fprintf(stderr, Str("Out of Memory\n"));
80           exit(7);
81         }
82         f->body = new;
83       }
84     }
85     if (n > 0) {
86       /* put the extra NULL chars to the end */
87       while (--n >= 0) {
88         f->body[f->p++] = '\0';
89         if (UNLIKELY(f->p >= f->len)) {
90           char *new = (char*) csound->ReAlloc(csound, f->body, f->len+=100);
91           if (UNLIKELY(new==NULL)) {
92             fprintf(stderr, Str("Out of Memory\n"));
93             exit(7);
94           }
95           f->body = new;
96         }
97       }
98     }
99     f->body[f->p] = '\0';
100 }
101 
corfile_flush(CSOUND * csound,CORFIL * f)102 void corfile_flush(CSOUND *csound, CORFIL *f)
103 {
104     char *new;
105     f->len = strlen(f->body)+1;
106     new = (char*)csound->ReAlloc(csound, f->body, f->len);
107     if (UNLIKELY(new==NULL)) {
108       fprintf(stderr, Str("Out of Memory\n"));
109       exit(7);
110     }
111     f->body = new;
112     f->p = 0;
113 }
114 
115 #undef corfile_length
corfile_length(CORFIL * f)116 int corfile_length(CORFIL *f)
117 {
118     return strlen(f->body);
119 }
120 
corfile_rm(CSOUND * csound,CORFIL ** ff)121 void corfile_rm(CSOUND *csound, CORFIL **ff)
122 {
123     CORFIL *f = *ff;
124     if (LIKELY(f!=NULL)) {
125       csound->Free(csound, f->body);
126       csound->Free(csound, f);
127       *ff = NULL;
128     }
129 }
130 
corfile_getc(CORFIL * f)131 int corfile_getc(CORFIL *f)
132 {
133     int c = f->body[f->p];
134     if (UNLIKELY(c=='\0')) return EOF;
135     f->p++;
136     return c;
137 }
138 
corfile_fgets(char * buff,int len,CORFIL * f)139 char *corfile_fgets(char *buff, int len, CORFIL *f)
140 {
141     int i;
142     char *p = &(f->body[f->p]), *q;
143     if (UNLIKELY(*p == '\0')) return NULL;
144     q = strchr(p, '\n');
145     i = (q-p);
146     if (UNLIKELY(i>=len)) i = len-1;
147     memcpy(buff, p, i);
148     f->p += i;
149     return buff;
150 }
151 
152 #undef corfile_ungetc
corfile_ungetc(CORFIL * f)153 void corfile_ungetc(CORFIL *f)
154 {
155     --f->p;
156 }
157 
corfile_get_flt(CORFIL * f)158 MYFLT corfile_get_flt(CORFIL *f)
159 {
160     int n = f->p;
161     MYFLT ans;
162     while (!isspace(f->body[++f->p]));
163     ans = (MYFLT) atof(&f->body[n]);
164     return ans;
165 }
166 
167 #undef corfile_rewind
corfile_rewind(CORFIL * f)168 void corfile_rewind(CORFIL *f)
169 {
170     f->p = 0;
171 }
172 
173 #undef corfile_reset
corfile_reset(CORFIL * f)174 void corfile_reset(CORFIL *f)
175 {
176     f->p = 0;
177     f->body[0] = '\0';
178 }
179 
180 #undef corfile_tell
corfile_tell(CORFIL * f)181 int corfile_tell(CORFIL *f)
182 {
183     return f->p;
184 }
185 
186 #undef corfile_set
corfile_set(CORFIL * f,int n)187 void corfile_set(CORFIL *f, int n)
188 {
189     f->p = n;
190 }
191 
corfile_seek(CORFIL * f,int n,int dir)192 void corfile_seek(CORFIL *f, int n, int dir)
193 {
194     if (dir == SEEK_SET) f->p = n;
195     else if (dir == SEEK_CUR) f->p += n;
196     else if (dir == SEEK_END) f->p = strlen(f->body)-n;
197     if (UNLIKELY(f->p > strlen(f->body))) {
198       printf("INTERNAL ERROR: Corfile seek out of range\n");
199       exit(1);
200     }
201 }
202 
203 
204 #undef corfile_body
corfile_body(CORFIL * f)205 char *corfile_body(CORFIL *f)
206 {
207     return f->body;
208 }
209 
210 #undef corfile_current
corfile_current(CORFIL * f)211 char *corfile_current(CORFIL *f)
212 {
213     return f->body+f->p;
214 }
215 
216 /* *** THIS NEEDS TO TAKE ACCOUNT OF SEARCH PATH *** */
217 void *fopen_path(CSOUND *csound, FILE **fp, const char *name,
218                  const char *basename, char *env, int fromScore);
copy_to_corefile(CSOUND * csound,const char * fname,const char * env,int fromScore)219 CORFIL *copy_to_corefile(CSOUND *csound, const char *fname,
220                          const char *env, int fromScore)
221 {
222     CORFIL *mm;
223     FILE *ff;
224     void *fd;
225     int n;
226     char buffer[1024];
227     if (UNLIKELY(fname==NULL)) {
228       csound->ErrorMsg(csound, Str("Null file name in copy_to_corefile"));
229       csound->LongJmp(csound, 1);
230     }
231 #ifdef HAVE_CURL
232     if (strstr(fname,"://")) {
233       /* **** Note the +2 is to skip spurous ./ inserted in a file name */
234       return copy_url_corefile(csound, fname+2, fromScore);
235     }
236 #endif
237     fd = fopen_path(csound, &ff, (char *)fname, NULL, (char *)env, fromScore);
238     if (UNLIKELY(ff==NULL)) return NULL;
239     mm = corfile_create_w(csound);
240     if (fromScore) corfile_putc(csound, '\n', mm);
241     memset(buffer, '\0', 1024);
242     while ((n = fread(buffer, 1, 1023, ff))) {
243       /* Need to lose \r characters  here */
244       /* while ((s = strchr(buffer, '\r'))) { */
245       /*   int k = n - (s-buffer); */
246       /*   memmove(s, s+1, k); */
247       /*   n--; */
248       /* } */
249       corfile_puts(csound, buffer, mm);
250       memset(buffer, '\0', 1024);
251     }
252     //#ifdef SCORE_PARSER
253     if (fromScore) {
254       corfile_puts(csound, "\ne\n#exit\n", mm);
255     }
256     //#endif
257     corfile_putc(csound, '\0', mm);     /* For use in bison/flex */
258     corfile_putc(csound, '\0', mm);     /* For use in bison/flex */
259     if (fromScore) corfile_flush(csound, mm);
260     csoundFileClose(csound, fd);
261     //if (fromScore) printf("Copy is >>%s<<\n", mm->body);
262     return mm;
263 }
264 
corfile_preputs(CSOUND * csound,const char * s,CORFIL * f)265 void corfile_preputs(CSOUND *csound, const char *s, CORFIL *f)
266 {
267     char *body = f->body;
268     f->body = (char*)csound->Malloc(csound, f->len=(strlen(body)+strlen(s)+1));
269     f->p = f->len-1;
270     strcpy(f->body, s); strcat(f->body, body);
271     csound->Free(csound, body);
272 }
273 
274 #ifdef HAVE_CURL
275 
276 #include <curl/curl.h>
277 
278 struct MemoryStruct {
279   char *memory;
280   size_t size;
281   CSOUND* cs;
282 };
283 
284 
285 static size_t
WriteMemoryCallback(void * contents,size_t size,size_t nmemb,void * userp)286 WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
287 {
288   size_t realsize = size * nmemb;
289   struct MemoryStruct *mem = (struct MemoryStruct *)userp;
290   CSOUND *csound = mem->cs;
291 
292   mem->memory = csound->ReAlloc(csound, mem->memory, mem->size + realsize + 1);
293   if (UNLIKELY(mem->memory == NULL)) {
294     /* out of memory! */
295     printf(Str("not enough memory (realloc returned NULL)\n"));
296     return 0;
297   }
298 
299   memcpy(&(mem->memory[mem->size]), contents, realsize);
300   mem->size += realsize;
301   mem->memory[mem->size] = 0;
302 
303   return realsize;
304 }
305 
copy_url_corefile(CSOUND * csound,const char * url,int fromScore)306 CORFIL *copy_url_corefile(CSOUND *csound, const char *url, int fromScore)
307 {
308     int n;
309     CURL *curl = curl_easy_init();
310     CORFIL *mm = corfile_create_w(csound);
311     struct MemoryStruct chunk;
312 
313     chunk.memory = csound->Malloc(csound, 1);  /* will grown */
314     chunk.size = 0;    /* no data at this point */
315     chunk.cs = csound;
316     curl_easy_setopt(curl, CURLOPT_URL, url);
317     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
318     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
319     curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
320     n = curl_easy_perform(curl);
321     if (UNLIKELY(n != CURLE_OK)) {
322       csound->Die(csound, Str("curl_easy_perform() failed: %s\n"),
323                   curl_easy_strerror(n));
324       /* return NULL ? */
325     }
326     curl_easy_cleanup(curl);
327     corfile_puts(csound, chunk.memory, mm);
328     corfile_putc(csound, '\0', mm);     /* For use in bison/flex */
329     corfile_putc(csound, '\0', mm);     /* For use in bison/flex */
330     if (fromScore) corfile_flush(csound, mm);
331     csound->Free(csound, chunk.memory);
332 
333     curl_global_cleanup();
334     return mm;
335 }
336 
337 #endif
338 
339 #if 0
340 int main(void)
341 {
342     CURL *curl_handle;
343     CURLcode res;
344 
345     struct MemoryStruct chunk;
346 
347     /* will grown as needed by the realloc above */
348     chunk.memory = csound->Malloc(csound, 1);
349     chunk.size = 0;    /* no data at this point */
350 
351     curl_global_init(CURL_GLOBAL_ALL);
352 
353     /* init the curl session */
354     curl_handle = curl_easy_init();
355 
356     /* specify URL to get */
357     curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.example.com/");
358 
359     /* send all data to this function  */
360     curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
361 
362     /* we pass our 'chunk' struct to the callback function */
363     curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
364 
365     /* some servers don't like requests that are made without a user-agent
366        field, so we provide one */
367     curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
368 
369     /* get it! */
370     res = curl_easy_perform(curl_handle);
371 
372     /* check for errors */
373     if (res != CURLE_OK) {
374       fprintf(stderr, "curl_easy_perform() failed: %s\n",
375               curl_easy_strerror(res));
376     }
377     else {
378       /*
379        * Now, our chunk.memory points to a memory block that is chunk.size
380        * bytes big and contains the remote file.
381        *
382        * Do something nice with it!
383        */
384 
385       printf("%lu bytes retrieved\n", (long)chunk.size);
386     }
387 
388     /* cleanup curl stuff */
389     curl_easy_cleanup(curl_handle);
390 
391     if (chunk.memory)
392       free(chunk.memory);
393 
394     /* we're done with libcurl, so clean it up */
395     curl_global_cleanup();
396 
397     return 0;
398 }
399 #endif
400 
401 #ifdef JPFF
402 /* Start of directory of corfiles currently unused except experimental in CsFileC */
403 typedef struct dir {
404   char       *name;
405   CORFIL     *corfile;
406   struct dir *next;
407 } CORDIR;
408 
add_corfile(CSOUND * csound,CORFIL * smpf,char * filename)409 void add_corfile(CSOUND* csound, CORFIL *smpf, char *filename)
410 {
411     CORDIR *entry = csound->Malloc(csound, sizeof(CORDIR));
412     entry->name = cs_strdup(csound, filename);
413     entry->corfile = smpf;
414     entry->next = (CORDIR *)csound->directory;
415     csound->directory = entry;
416 }
417 #endif
418