bio-bigwig 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,296 @@
1
+ #ifndef NOCURL
2
+ #include <curl/curl.h>
3
+ #endif
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <unistd.h>
8
+ #include "bigWigIO.h"
9
+ #include <inttypes.h>
10
+ #include <errno.h>
11
+
12
+ size_t GLOBAL_DEFAULTBUFFERSIZE;
13
+
14
+ #ifndef NOCURL
15
+ uint64_t getContentLength(const URL_t *URL) {
16
+ double size;
17
+ if(curl_easy_getinfo(URL->x.curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size) != CURLE_OK) {
18
+ return 0;
19
+ }
20
+ if(size== -1.0) return 0;
21
+ return (uint64_t) size;
22
+ }
23
+
24
+ //Fill the buffer, note that URL may be left in an unusable state on error!
25
+ CURLcode urlFetchData(URL_t *URL, unsigned long bufSize) {
26
+ CURLcode rv;
27
+ char range[1024];
28
+
29
+ if(URL->filePos != (size_t) -1) URL->filePos += URL->bufLen;
30
+ else URL->filePos = 0;
31
+
32
+ URL->bufPos = URL->bufLen = 0; //Otherwise, we can't copy anything into the buffer!
33
+ sprintf(range,"%lu-%lu", URL->filePos, URL->filePos+bufSize-1);
34
+ rv = curl_easy_setopt(URL->x.curl, CURLOPT_RANGE, range);
35
+ if(rv != CURLE_OK) {
36
+ fprintf(stderr, "[urlFetchData] Couldn't set the range (%s)\n", range);
37
+ return rv;
38
+ }
39
+
40
+ rv = curl_easy_perform(URL->x.curl);
41
+ errno = 0; //Sometimes curl_easy_perform leaves a random errno remnant
42
+ return rv;
43
+ }
44
+
45
+ //Read data into a buffer, ideally from a buffer already in memory
46
+ //The loop is likely no longer needed.
47
+ size_t url_fread(void *obuf, size_t obufSize, URL_t *URL) {
48
+ size_t remaining = obufSize, fetchSize;
49
+ void *p = obuf;
50
+ CURLcode rv;
51
+
52
+ while(remaining) {
53
+ if(!URL->bufLen) {
54
+ rv = urlFetchData(URL, URL->bufSize);
55
+ if(rv != CURLE_OK) {
56
+ fprintf(stderr, "[url_fread] urlFetchData (A) returned %s\n", curl_easy_strerror(rv));
57
+ return 0;
58
+ }
59
+ } else if(URL->bufLen < URL->bufPos + remaining) { //Copy the remaining buffer and reload the buffer as needed
60
+ p = memcpy(p, URL->memBuf+URL->bufPos, URL->bufLen - URL->bufPos);
61
+ if(!p) return 0;
62
+ p += URL->bufLen - URL->bufPos;
63
+ remaining -= URL->bufLen - URL->bufPos;
64
+ if(remaining) {
65
+ if(!URL->isCompressed) {
66
+ fetchSize = URL->bufSize;
67
+ } else {
68
+ fetchSize = (remaining<URL->bufSize)?remaining:URL->bufSize;
69
+ }
70
+ rv = urlFetchData(URL, fetchSize);
71
+ if(rv != CURLE_OK) {
72
+ fprintf(stderr, "[url_fread] urlFetchData (B) returned %s\n", curl_easy_strerror(rv));
73
+ return 0;
74
+ }
75
+ }
76
+ } else {
77
+ p = memcpy(p, URL->memBuf+URL->bufPos, remaining);
78
+ if(!p) return 0;
79
+ URL->bufPos += remaining;
80
+ remaining = 0;
81
+ }
82
+ }
83
+ return obufSize;
84
+ }
85
+ #endif
86
+
87
+ //Returns the number of bytes requested or a smaller number on error
88
+ //Note that in the case of remote files, the actual amount read may be less than the return value!
89
+ size_t urlRead(URL_t *URL, void *buf, size_t bufSize) {
90
+ #ifndef NOCURL
91
+ if(URL->type==0) {
92
+ return fread(buf, bufSize, 1, URL->x.fp)*bufSize;
93
+ } else {
94
+ return url_fread(buf, bufSize, URL);
95
+ }
96
+ #else
97
+ return fread(buf, bufSize, 1, URL->x.fp)*bufSize;
98
+ #endif
99
+ }
100
+
101
+ size_t bwFillBuffer(const void *inBuf, size_t l, size_t nmemb, void *pURL) {
102
+ URL_t *URL = (URL_t*) pURL;
103
+ void *p = URL->memBuf;
104
+ size_t copied = l*nmemb;
105
+ if(!p) return 0;
106
+
107
+ p += URL->bufLen;
108
+ if(l*nmemb > URL->bufSize - URL->bufPos) { //We received more than we can store!
109
+ copied = URL->bufSize - URL->bufLen;
110
+ }
111
+ memcpy(p, inBuf, copied);
112
+ URL->bufLen += copied;
113
+
114
+ if(!URL->memBuf) return 0; //signal error
115
+ return copied;
116
+ }
117
+
118
+ //Seek to an arbitrary location, returning a CURLcode
119
+ //Note that a local file returns CURLE_OK on success or CURLE_FAILED_INIT on any error;
120
+ CURLcode urlSeek(URL_t *URL, size_t pos) {
121
+ #ifndef NOCURL
122
+ char range[1024];
123
+ CURLcode rv;
124
+
125
+ if(URL->type == BWG_FILE) {
126
+ #endif
127
+ if(fseek(URL->x.fp, pos, SEEK_SET) == 0) {
128
+ errno = 0;
129
+ return CURLE_OK;
130
+ } else {
131
+ return CURLE_FAILED_INIT; //This is arbitrary
132
+ }
133
+ #ifndef NOCURL
134
+ } else {
135
+ //If the location is covered by the buffer then don't seek!
136
+ if(pos < URL->filePos || pos >= URL->filePos+URL->bufLen) {
137
+ URL->filePos = pos;
138
+ URL->bufLen = 0; //Otherwise, filePos will get incremented on the next read!
139
+ URL->bufPos = 0;
140
+ //Maybe this works for FTP?
141
+ sprintf(range,"%lu-%lu", pos, pos+URL->bufSize-1);
142
+ rv = curl_easy_setopt(URL->x.curl, CURLOPT_RANGE, range);
143
+ if(rv != CURLE_OK) {
144
+ fprintf(stderr, "[urlSeek] Couldn't set the range (%s)\n", range);
145
+ return rv;
146
+ }
147
+ rv = curl_easy_perform(URL->x.curl);
148
+ if(rv != CURLE_OK) {
149
+ fprintf(stderr, "[urlSeek] curl_easy_perform received an error!\n");
150
+ }
151
+ errno = 0; //Don't propogate remnant resolved libCurl errors
152
+ return rv;
153
+ } else {
154
+ URL->bufPos = pos-URL->filePos;
155
+ return CURLE_OK;
156
+ }
157
+ }
158
+ #endif
159
+ }
160
+
161
+ URL_t *urlOpen(const char *fname, CURLcode (*callBack)(CURL*), const char *mode) {
162
+ URL_t *URL = calloc(1, sizeof(URL_t));
163
+ if(!URL) return NULL;
164
+ char *url = NULL, *req = NULL;
165
+ #ifndef NOCURL
166
+ CURLcode code;
167
+ char range[1024];
168
+ #endif
169
+
170
+ URL->fname = fname;
171
+
172
+ if((!mode) || (strchr(mode, 'w') == 0)) {
173
+ //Set the protocol
174
+ #ifndef NOCURL
175
+ if(strncmp(fname, "http://", 7) == 0) URL->type = BWG_HTTP;
176
+ else if(strncmp(fname, "https://", 8) == 0) URL->type = BWG_HTTPS;
177
+ else if(strncmp(fname, "ftp://", 6) == 0) URL->type = BWG_FTP;
178
+ else URL->type = BWG_FILE;
179
+ #else
180
+ URL->type = BWG_FILE;
181
+ #endif
182
+
183
+ //local file?
184
+ if(URL->type == BWG_FILE) {
185
+ URL->filePos = -1; //This signals that nothing has been read
186
+ URL->x.fp = fopen(fname, "rb");
187
+ if(!(URL->x.fp)) {
188
+ free(URL);
189
+ fprintf(stderr, "[urlOpen] Couldn't open %s for reading\n", fname);
190
+ return NULL;
191
+ }
192
+ #ifndef NOCURL
193
+ } else {
194
+ //Remote file, set up the memory buffer and get CURL ready
195
+ URL->memBuf = malloc(GLOBAL_DEFAULTBUFFERSIZE);
196
+ if(!(URL->memBuf)) {
197
+ free(URL);
198
+ fprintf(stderr, "[urlOpen] Couldn't allocate enough space for the file buffer!\n");
199
+ return NULL;
200
+ }
201
+ URL->bufSize = GLOBAL_DEFAULTBUFFERSIZE;
202
+ URL->x.curl = curl_easy_init();
203
+ if(!(URL->x.curl)) {
204
+ fprintf(stderr, "[urlOpen] curl_easy_init() failed!\n");
205
+ goto error;
206
+ }
207
+ //Negotiate a reasonable HTTP authentication method
208
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY) != CURLE_OK) {
209
+ fprintf(stderr, "[urlOpen] Failed instructing curl to use any HTTP authentication it finds to be suitable!\n");
210
+ goto error;
211
+ }
212
+ //Follow redirects
213
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) {
214
+ fprintf(stderr, "[urlOpen] Failed instructing curl to follow redirects!\n");
215
+ goto error;
216
+ }
217
+ //Set the URL
218
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_URL, fname) != CURLE_OK) {
219
+ fprintf(stderr, "[urlOpen] Couldn't set CURLOPT_URL!\n");
220
+ goto error;
221
+ }
222
+ //Set the range, which doesn't do anything for HTTP
223
+ sprintf(range, "0-%lu", URL->bufSize-1);
224
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_RANGE, range) != CURLE_OK) {
225
+ fprintf(stderr, "[urlOpen] Couldn't set CURLOPT_RANGE (%s)!\n", range);
226
+ goto error;
227
+ }
228
+ //Set the callback info, which means we no longer need to directly deal with sockets and header!
229
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_WRITEFUNCTION, bwFillBuffer) != CURLE_OK) {
230
+ fprintf(stderr, "[urlOpen] Couldn't set CURLOPT_WRITEFUNCTION!\n");
231
+ goto error;
232
+ }
233
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_WRITEDATA, (void*)URL) != CURLE_OK) {
234
+ fprintf(stderr, "[urlOpen] Couldn't set CURLOPT_WRITEDATA!\n");
235
+ goto error;
236
+ }
237
+ //Ignore certificate errors with https, libcurl just isn't reliable enough with conda
238
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_SSL_VERIFYPEER, 0) != CURLE_OK) {
239
+ fprintf(stderr, "[urlOpen] Couldn't set CURLOPT_SSL_VERIFYPEER to 0!\n");
240
+ goto error;
241
+ }
242
+ if(curl_easy_setopt(URL->x.curl, CURLOPT_SSL_VERIFYHOST, 0) != CURLE_OK) {
243
+ fprintf(stderr, "[urlOpen] Couldn't set CURLOPT_SSL_VERIFYHOST to 0!\n");
244
+ goto error;
245
+ }
246
+ if(callBack) {
247
+ code = callBack(URL->x.curl);
248
+ if(code != CURLE_OK) {
249
+ fprintf(stderr, "[urlOpen] The user-supplied call back function returned an error: %s\n", curl_easy_strerror(code));
250
+ goto error;
251
+ }
252
+ }
253
+ code = curl_easy_perform(URL->x.curl);
254
+ errno = 0; //Sometimes curl_easy_perform leaves a random errno remnant
255
+ if(code != CURLE_OK) {
256
+ fprintf(stderr, "[urlOpen] curl_easy_perform received an error: %s\n", curl_easy_strerror(code));
257
+ goto error;
258
+ }
259
+ #endif
260
+ }
261
+ } else {
262
+ URL->type = BWG_FILE;
263
+ URL->x.fp = fopen(fname, mode);
264
+ if(!(URL->x.fp)) {
265
+ free(URL);
266
+ fprintf(stderr, "[urlOpen] Couldn't open %s for writing\n", fname);
267
+ return NULL;
268
+ }
269
+ }
270
+ if(url) free(url);
271
+ if(req) free(req);
272
+ return URL;
273
+
274
+ #ifndef NOCURL
275
+ error:
276
+ if(url) free(url);
277
+ if(req) free(req);
278
+ free(URL->memBuf);
279
+ curl_easy_cleanup(URL->x.curl);
280
+ free(URL);
281
+ return NULL;
282
+ #endif
283
+ }
284
+
285
+ //Performs the necessary free() operations and handles cleaning up curl
286
+ void urlClose(URL_t *URL) {
287
+ if(URL->type == BWG_FILE) {
288
+ fclose(URL->x.fp);
289
+ #ifndef NOCURL
290
+ } else {
291
+ free(URL->memBuf);
292
+ curl_easy_cleanup(URL->x.curl);
293
+ #endif
294
+ }
295
+ free(URL);
296
+ }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bio
4
4
  class BigWig
5
- VERSION = "0.0.2"
5
+ VERSION = "0.0.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bio-bigwig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
@@ -24,6 +24,16 @@ files:
24
24
  - ext/bio/bigwig/bigwigext.c
25
25
  - ext/bio/bigwig/bigwigext.h
26
26
  - ext/bio/bigwig/extconf.rb
27
+ - ext/bio/bigwig/libBigWig/LICENSE
28
+ - ext/bio/bigwig/libBigWig/bigWig.h
29
+ - ext/bio/bigwig/libBigWig/bigWigIO.h
30
+ - ext/bio/bigwig/libBigWig/bwCommon.h
31
+ - ext/bio/bigwig/libBigWig/bwRead.c
32
+ - ext/bio/bigwig/libBigWig/bwStats.c
33
+ - ext/bio/bigwig/libBigWig/bwValues.c
34
+ - ext/bio/bigwig/libBigWig/bwValues.h
35
+ - ext/bio/bigwig/libBigWig/bwWrite.c
36
+ - ext/bio/bigwig/libBigWig/io.c
27
37
  - lib/bio/bigwig.rb
28
38
  - lib/bio/bigwig/version.rb
29
39
  homepage: https://github.com/kojix2/bio-bigwig