Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2019
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / ISO Media File Format sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/isomedia_dev.h>
27 : #include <gpac/network.h>
28 : #include <gpac/thread.h>
29 :
30 :
31 : /*File Mapping object, read-only mode on complete files (no download)*/
32 : //#define GF_ISOM_DATA_FILE_MAPPING 0x02
33 :
34 : #ifndef GPAC_DISABLE_ISOM
35 :
36 :
37 17096 : void gf_isom_datamap_del(GF_DataMap *ptr)
38 : {
39 17096 : if (!ptr) return;
40 :
41 16430 : if (ptr->szName) gf_free(ptr->szName);
42 :
43 : //then delete the structure itself....
44 16430 : switch (ptr->type) {
45 : //file-based
46 16430 : case GF_ISOM_DATA_FILE:
47 : case GF_ISOM_DATA_MEM:
48 16430 : gf_isom_fdm_del((GF_FileDataMap *)ptr);
49 16430 : break;
50 : #if 0
51 : case GF_ISOM_DATA_FILE_MAPPING:
52 : gf_isom_fmo_del((GF_FileMappingDataMap *)ptr);
53 : break;
54 : #endif
55 0 : default:
56 0 : if (ptr->bs) gf_bs_del(ptr->bs);
57 0 : gf_free(ptr);
58 0 : break;
59 : }
60 : }
61 :
62 : //Close a data entry
63 646743 : void gf_isom_datamap_close(GF_MediaInformationBox *minf)
64 : {
65 : GF_DataEntryBox *ent = NULL;
66 646743 : if (!minf || !minf->dataHandler) return;
67 :
68 646743 : if (minf->dataInformation && minf->dataInformation->dref) {
69 646737 : ent = (GF_DataEntryBox*)gf_list_get(minf->dataInformation->dref->child_boxes, minf->dataEntryIndex - 1);
70 : }
71 :
72 : //if ent NULL, the data entry was not used (smooth)
73 646737 : if (ent == NULL) return;
74 :
75 : //self contained, do nothing
76 646735 : switch (ent->type) {
77 646732 : case GF_ISOM_BOX_TYPE_URL:
78 : case GF_ISOM_BOX_TYPE_URN:
79 646732 : if (ent->flags == 1) return;
80 : break;
81 : default:
82 : return;
83 : }
84 :
85 : //finally close it
86 0 : gf_isom_datamap_del(minf->dataHandler);
87 0 : minf->dataHandler = NULL;
88 : }
89 :
90 : /*cf below, we disable filedatamap since it tricks mem usage on w32*/
91 : #if 0
92 : static Bool IsLargeFile(char *path)
93 : {
94 : #ifndef _WIN32_WCE
95 : FILE *stream;
96 : s64 size;
97 : stream = gf_fopen(path, "rb");
98 : if (!stream) return 0;
99 : size = gf_fsize(stream);
100 : gf_fclose(stream);
101 : if (size == -1L) return 0;
102 : if (size > 0xFFFFFFFF) return 1;
103 : #endif
104 : return 0;
105 : }
106 : #endif
107 :
108 :
109 : //Special constructor, we need some error feedback...
110 :
111 16432 : GF_Err gf_isom_datamap_new(const char *location, const char *parentPath, u8 mode, GF_DataMap **outDataMap)
112 : {
113 : Bool extern_file;
114 : char *sPath;
115 16432 : *outDataMap = NULL;
116 :
117 : //if nothing specified, this is a MEMORY data map
118 16432 : if (!location) {
119 1 : *outDataMap = gf_isom_fdm_new(location, GF_ISOM_DATA_MAP_WRITE);
120 1 : if (!(*outDataMap)) {
121 : return GF_IO_ERR;
122 : }
123 1 : return GF_OK;
124 : }
125 : //we need a temp file ...
126 16431 : if (!strcmp(location, "_gpac_isobmff_tmp_edit")) {
127 : #ifndef GPAC_DISABLE_ISOM_WRITE
128 1169 : *outDataMap = gf_isom_fdm_new_temp(parentPath);
129 1169 : if (! (*outDataMap)) {
130 : return GF_IO_ERR;
131 : }
132 1169 : return GF_OK;
133 : #else
134 : return GF_NOT_SUPPORTED;
135 : #endif
136 15262 : } else if (!strncmp(location, "gmem://", 7) || !strncmp(location, "gfio://", 7)) {
137 6047 : *outDataMap = gf_isom_fdm_new(location, GF_ISOM_DATA_MAP_READ);
138 6047 : if (! (*outDataMap)) {
139 : return GF_IO_ERR;
140 : }
141 6047 : return GF_OK;
142 9215 : } else if (!strcmp(location, "_gpac_isobmff_redirect")) {
143 2844 : *outDataMap = gf_isom_fdm_new(location, mode);
144 2844 : if (! (*outDataMap)) {
145 : return GF_IO_ERR;
146 : }
147 2844 : return GF_OK;
148 : }
149 :
150 6371 : extern_file = !gf_url_is_local(location);
151 :
152 6371 : if (mode == GF_ISOM_DATA_MAP_EDIT) {
153 : //we need a local file for edition!!!
154 221 : if (extern_file) return GF_ISOM_INVALID_MODE;
155 : //OK, switch back to READ mode
156 : mode = GF_ISOM_DATA_MAP_READ;
157 : }
158 :
159 : //TEMP: however, only support for file right now (we'd have to add some callback functions at some point)
160 6371 : if (extern_file) {
161 : return GF_NOT_SUPPORTED;
162 : }
163 :
164 6371 : sPath = gf_url_concatenate(parentPath, location);
165 6371 : if (sPath == NULL) {
166 : return GF_URL_ERROR;
167 : }
168 :
169 6371 : if (mode == GF_ISOM_DATA_MAP_READ_ONLY) {
170 : mode = GF_ISOM_DATA_MAP_READ;
171 :
172 : #if 0 //file mapping is disabled
173 : if (IsLargeFile(sPath)) {
174 : *outDataMap = gf_isom_fdm_new(sPath, mode);
175 : } else {
176 : *outDataMap = gf_isom_fmo_new(sPath, mode);
177 : }
178 : #else
179 5503 : *outDataMap = gf_isom_fdm_new(sPath, mode);
180 : #endif
181 : } else {
182 868 : *outDataMap = gf_isom_fdm_new(sPath, mode);
183 868 : if (*outDataMap) {
184 868 : (*outDataMap)->szName = sPath;
185 : sPath = NULL;
186 : }
187 : }
188 :
189 : if (sPath) {
190 5503 : gf_free(sPath);
191 : }
192 6371 : if (! (*outDataMap)) {
193 : return GF_URL_ERROR;
194 : }
195 :
196 6369 : return GF_OK;
197 : }
198 :
199 : //Open a data entry of a track
200 : //Edit is used to switch between original and edition file
201 646440 : GF_Err gf_isom_datamap_open(GF_MediaBox *mdia, u32 dataRefIndex, u8 Edit)
202 : {
203 : GF_DataEntryBox *ent;
204 : GF_MediaInformationBox *minf;
205 : u32 SelfCont, count;
206 : GF_Err e = GF_OK;
207 646440 : if ((mdia == NULL) || (! mdia->information) || !dataRefIndex)
208 : return GF_ISOM_INVALID_MEDIA;
209 :
210 : minf = mdia->information;
211 646440 : if (!minf->dataInformation || !minf->dataInformation->dref)
212 : return GF_ISOM_INVALID_MEDIA;
213 :
214 646440 : count = gf_list_count(minf->dataInformation->dref->child_boxes);
215 646440 : if (!count) {
216 : SelfCont = 1;
217 : ent = NULL;
218 : } else {
219 646440 : if (dataRefIndex > gf_list_count(minf->dataInformation->dref->child_boxes))
220 : return GF_BAD_PARAM;
221 :
222 646440 : ent = (GF_DataEntryBox*)gf_list_get(minf->dataInformation->dref->child_boxes, dataRefIndex - 1);
223 646440 : if (ent == NULL) return GF_ISOM_INVALID_MEDIA;
224 :
225 : //if the current dataEntry is the desired one, and not self contained, return
226 646440 : if ((minf->dataEntryIndex == dataRefIndex) && (ent->flags != 1)) {
227 : return GF_OK;
228 : }
229 :
230 : SelfCont = 0;
231 646440 : switch (ent->type) {
232 646437 : case GF_ISOM_BOX_TYPE_URL:
233 : case GF_ISOM_BOX_TYPE_URN:
234 646437 : if (ent->flags == 1) SelfCont = 1;
235 : break;
236 : default:
237 : SelfCont = 1;
238 : break;
239 : }
240 : }
241 :
242 : //we need to open a new one
243 : //first close the existing one
244 646440 : if (minf->dataHandler) gf_isom_datamap_close(minf);
245 :
246 : //if self-contained, assign the input file
247 646440 : if (SelfCont) {
248 : //if no edit, open the input file
249 646440 : if (!Edit) {
250 66652 : if (mdia->mediaTrack->moov->mov->movieFileMap == NULL) return GF_ISOM_INVALID_FILE;
251 66652 : minf->dataHandler = mdia->mediaTrack->moov->mov->movieFileMap;
252 : } else {
253 : #ifndef GPAC_DISABLE_ISOM_WRITE
254 579788 : if (mdia->mediaTrack->moov->mov->editFileMap == NULL) return GF_ISOM_INVALID_FILE;
255 579788 : minf->dataHandler = mdia->mediaTrack->moov->mov->editFileMap;
256 : #else
257 : //this should never be the case in an read-only MP4 file
258 : return GF_BAD_PARAM;
259 : #endif
260 : }
261 : //else this is a URL (read mode only)
262 : } else {
263 0 : e = gf_isom_datamap_new(ent->location, mdia->mediaTrack->moov->mov->fileName ? mdia->mediaTrack->moov->mov->fileName : mdia->mediaTrack->moov->mov->finalName, GF_ISOM_DATA_MAP_READ, & mdia->information->dataHandler);
264 0 : if (e) return (e==GF_URL_ERROR) ? GF_ISOM_UNKNOWN_DATA_REF : e;
265 : }
266 : //OK, set the data entry index
267 646440 : minf->dataEntryIndex = dataRefIndex;
268 646440 : return GF_OK;
269 : }
270 :
271 : //return the NB of bytes actually read (used for HTTP, ...) in case file is uncomplete
272 1546920 : u32 gf_isom_datamap_get_data(GF_DataMap *map, u8 *buffer, u32 bufferLength, u64 Offset)
273 : {
274 1546920 : if (!map || !buffer) return 0;
275 :
276 1546920 : switch (map->type) {
277 1546920 : case GF_ISOM_DATA_FILE:
278 : case GF_ISOM_DATA_MEM:
279 1546920 : return gf_isom_fdm_get_data((GF_FileDataMap *)map, buffer, bufferLength, Offset);
280 :
281 : #if 0
282 : case GF_ISOM_DATA_FILE_MAPPING:
283 : return gf_isom_fmo_get_data((GF_FileMappingDataMap *)map, buffer, bufferLength, Offset);
284 : #endif
285 :
286 : default:
287 : return 0;
288 : }
289 : }
290 :
291 453 : void gf_isom_datamap_flush(GF_DataMap *map)
292 : {
293 453 : if (!map) return;
294 :
295 453 : if (map->type == GF_ISOM_DATA_FILE || map->type == GF_ISOM_DATA_MEM) {
296 : GF_FileDataMap *fdm = (GF_FileDataMap *)map;
297 453 : gf_bs_flush(fdm->bs);
298 : }
299 : }
300 :
301 : #ifndef GPAC_DISABLE_ISOM_WRITE
302 :
303 : u64 FDM_GetTotalOffset(GF_FileDataMap *ptr);
304 : GF_Err FDM_AddData(GF_FileDataMap *ptr, char *data, u32 dataSize);
305 :
306 560921 : u64 gf_isom_datamap_get_offset(GF_DataMap *map)
307 : {
308 560921 : if (!map) return 0;
309 :
310 560921 : switch (map->type) {
311 : case GF_ISOM_DATA_FILE:
312 560921 : return FDM_GetTotalOffset((GF_FileDataMap *)map);
313 0 : case GF_ISOM_DATA_MEM:
314 0 : return gf_bs_get_position(map->bs);
315 : default:
316 : return 0;
317 : }
318 : }
319 :
320 :
321 560614 : GF_Err gf_isom_datamap_add_data(GF_DataMap *ptr, u8 *data, u32 dataSize)
322 : {
323 560614 : if (!ptr || !data|| !dataSize) return GF_BAD_PARAM;
324 :
325 560614 : switch (ptr->type) {
326 560614 : case GF_ISOM_DATA_FILE:
327 : case GF_ISOM_DATA_MEM:
328 560614 : return FDM_AddData((GF_FileDataMap *)ptr, data, dataSize);
329 : default:
330 : return GF_NOT_SUPPORTED;
331 : }
332 : }
333 :
334 1169 : GF_DataMap *gf_isom_fdm_new_temp(const char *sPath)
335 : {
336 : GF_FileDataMap *tmp;
337 1169 : GF_SAFEALLOC(tmp, GF_FileDataMap);
338 1169 : if (!tmp) return NULL;
339 :
340 1169 : tmp->type = GF_ISOM_DATA_FILE;
341 1169 : tmp->mode = GF_ISOM_DATA_MAP_WRITE;
342 :
343 1169 : if (!sPath) {
344 1169 : tmp->stream = gf_file_temp(&tmp->temp_file);
345 : } else {
346 : char szPath[GF_MAX_PATH];
347 0 : if ((sPath[strlen(sPath)-1] != '\\') && (sPath[strlen(sPath)-1] != '/')) {
348 : sprintf(szPath, "%s%c%p_isotmp", sPath, GF_PATH_SEPARATOR, (void*) tmp);
349 : } else {
350 : sprintf(szPath, "%s%p_isotmp", sPath, (void*) tmp);
351 : }
352 0 : tmp->stream = gf_fopen(szPath, "w+b");
353 0 : tmp->temp_file = gf_strdup(szPath);
354 : }
355 1169 : if (!tmp->stream) {
356 0 : if (tmp->temp_file) gf_free(tmp->temp_file);
357 0 : gf_free(tmp);
358 0 : return NULL;
359 : }
360 1169 : tmp->bs = gf_bs_from_file(tmp->stream, GF_BITSTREAM_WRITE);
361 1169 : if (!tmp->bs) {
362 0 : gf_fclose(tmp->stream);
363 0 : gf_free(tmp);
364 0 : return NULL;
365 : }
366 : return (GF_DataMap *)tmp;
367 : }
368 :
369 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
370 :
371 : #include <errno.h>
372 : #include <string.h>
373 15263 : GF_DataMap *gf_isom_fdm_new(const char *sPath, u8 mode)
374 : {
375 : u8 bs_mode;
376 : GF_FileDataMap *tmp;
377 15263 : GF_SAFEALLOC(tmp, GF_FileDataMap);
378 15263 : if (!tmp) return NULL;
379 :
380 15263 : tmp->mode = mode;
381 :
382 15263 : if (sPath == NULL) {
383 1 : tmp->type = GF_ISOM_DATA_MEM;
384 1 : tmp->bs = gf_bs_new (NULL, 0, GF_BITSTREAM_WRITE);
385 1 : if (!tmp->bs) {
386 0 : gf_free(tmp);
387 0 : return NULL;
388 : }
389 : return (GF_DataMap *)tmp;
390 : }
391 :
392 15262 : tmp->type = GF_ISOM_DATA_FILE;
393 : #ifndef GPAC_DISABLE_ISOM_WRITE
394 : //open a temp file
395 15262 : if (!strcmp(sPath, "_gpac_isobmff_tmp_edit")) {
396 : //create a temp file (that only occurs in EDIT/WRITE mode)
397 0 : tmp->stream = gf_file_temp(&tmp->temp_file);
398 : // bs_mode = GF_BITSTREAM_READ;
399 : }
400 : #endif
401 15262 : if (!strncmp(sPath, "gmem://", 7)) {
402 6042 : if (sscanf(sPath, "gmem://%p", &tmp->blob) != 1)
403 : return NULL;
404 6042 : tmp->bs = gf_bs_new(tmp->blob->data, tmp->blob->size, GF_BITSTREAM_READ);
405 6042 : if (!tmp->bs) {
406 0 : gf_free(tmp);
407 0 : return NULL;
408 : }
409 : return (GF_DataMap *)tmp;
410 : }
411 :
412 9220 : switch (mode) {
413 6368 : case GF_ISOM_DATA_MAP_READ:
414 6368 : if (!tmp->stream) tmp->stream = gf_fopen(sPath, "rb");
415 : bs_mode = GF_BITSTREAM_READ;
416 : break;
417 : ///we open the file in READ/WRITE mode, in case
418 2852 : case GF_ISOM_DATA_MAP_WRITE:
419 2852 : if (!strcmp(sPath, "_gpac_isobmff_redirect")) {
420 2844 : tmp->stream = NULL;
421 2844 : tmp->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
422 : } else {
423 8 : if (!strcmp(sPath, "std")) {
424 0 : tmp->stream = stdout;
425 0 : tmp->is_stdout = 1;
426 : }
427 :
428 8 : if (!tmp->stream) tmp->stream = gf_fopen(sPath, "w+b");
429 8 : if (!tmp->stream) tmp->stream = gf_fopen(sPath, "wb");
430 : }
431 : bs_mode = GF_BITSTREAM_WRITE;
432 : break;
433 : ///we open the file in CAT mode, in case
434 0 : case GF_ISOM_DATA_MAP_CAT:
435 0 : if (!strcmp(sPath, "_gpac_isobmff_redirect")) {
436 0 : tmp->stream = NULL;
437 0 : tmp->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
438 : } else {
439 0 : if (!strcmp(sPath, "std")) {
440 0 : tmp->stream = stdout;
441 0 : tmp->is_stdout = 1;
442 : }
443 :
444 0 : if (!tmp->stream) tmp->stream = gf_fopen(sPath, "a+b");
445 0 : if (tmp->stream) gf_fseek(tmp->stream, 0, SEEK_END);
446 : }
447 : bs_mode = GF_BITSTREAM_WRITE;
448 : break;
449 0 : default:
450 0 : gf_free(tmp);
451 0 : return NULL;
452 : }
453 9220 : if (!tmp->stream && !tmp->bs) {
454 2 : gf_free(tmp);
455 2 : return NULL;
456 : }
457 9218 : if (!tmp->bs)
458 6374 : tmp->bs = gf_bs_from_file(tmp->stream, bs_mode);
459 :
460 9218 : if (!tmp->bs) {
461 0 : gf_fclose(tmp->stream);
462 0 : gf_free(tmp);
463 0 : return NULL;
464 : }
465 : return (GF_DataMap *)tmp;
466 : }
467 :
468 16430 : void gf_isom_fdm_del(GF_FileDataMap *ptr)
469 : {
470 16430 : if (!ptr || (ptr->type != GF_ISOM_DATA_FILE && ptr->type != GF_ISOM_DATA_MEM)) return;
471 16430 : if (ptr->bs) gf_bs_del(ptr->bs);
472 16430 : if (ptr->stream && !ptr->is_stdout)
473 7543 : gf_fclose(ptr->stream);
474 :
475 : #ifndef GPAC_DISABLE_ISOM_WRITE
476 16430 : if (ptr->temp_file) {
477 0 : gf_file_delete(ptr->temp_file);
478 0 : gf_free(ptr->temp_file);
479 : }
480 : #endif
481 16430 : gf_free(ptr);
482 : }
483 :
484 1546920 : u32 gf_isom_fdm_get_data(GF_FileDataMap *ptr, u8 *buffer, u32 bufferLength, u64 fileOffset)
485 : {
486 : u32 bytesRead;
487 :
488 : //can we seek till that point ???
489 1546920 : if (fileOffset > gf_bs_get_size(ptr->bs))
490 : return 0;
491 :
492 1546920 : if (ptr->blob) {
493 49685 : gf_mx_p(ptr->blob->mx);
494 49685 : gf_bs_reassign_buffer(ptr->bs, ptr->blob->data, ptr->blob->size);
495 49685 : if (gf_bs_seek(ptr->bs, fileOffset) != GF_OK) {
496 0 : gf_mx_v(ptr->blob->mx);
497 0 : return 0;
498 : }
499 1497235 : } else if (gf_bs_get_position(ptr->bs) != fileOffset) {
500 : //we are not at the previous location, do a seek
501 122546 : if (gf_bs_seek(ptr->bs, fileOffset) != GF_OK) return 0;
502 : }
503 1546920 : ptr->curPos = fileOffset;
504 :
505 : //read our data.
506 1546920 : bytesRead = gf_bs_read_data(ptr->bs, buffer, bufferLength);
507 : //update our cache
508 1546920 : if (bytesRead == bufferLength) {
509 1546920 : ptr->curPos += bytesRead;
510 : } else {
511 0 : gf_bs_get_refreshed_size(ptr->bs);
512 0 : gf_bs_seek(ptr->bs, fileOffset);
513 0 : bytesRead = gf_bs_read_data(ptr->bs, buffer, bufferLength);
514 : //update our cache
515 0 : if (bytesRead == bufferLength) {
516 0 : ptr->curPos += bytesRead;
517 : } else {
518 0 : gf_bs_seek(ptr->bs, ptr->curPos);
519 : bytesRead = 0;
520 : }
521 : }
522 1546920 : ptr->last_acces_was_read = 1;
523 :
524 1546920 : if (ptr->blob) {
525 49685 : gf_mx_v(ptr->blob->mx);
526 : }
527 : return bytesRead;
528 : }
529 :
530 :
531 : #ifndef GPAC_DISABLE_ISOM_WRITE
532 :
533 :
534 0 : u64 FDM_GetTotalOffset(GF_FileDataMap *ptr)
535 : {
536 0 : if (!ptr) return 0;
537 : //the pos is not always at the end
538 : //this function is called to set up the chunks
539 : //so we need the next WRITE offset
540 560921 : return gf_bs_get_size(ptr->bs);
541 : }
542 :
543 560614 : GF_Err FDM_AddData(GF_FileDataMap *ptr, char *data, u32 dataSize)
544 : {
545 : u32 ret;
546 : u64 orig;
547 560614 : if (ptr->mode == GF_ISOM_DATA_MAP_READ) return GF_BAD_PARAM;
548 :
549 560614 : orig = gf_bs_get_size(ptr->bs);
550 :
551 : /*last access was read, seek to end of file*/
552 560614 : if (ptr->last_acces_was_read) {
553 5011 : gf_bs_seek(ptr->bs, orig);
554 5011 : ptr->last_acces_was_read = 0;
555 : }
556 : //OK, write our stuff to the datamap...
557 : //we don't use bs here cause we want to know more about what has been written
558 560614 : ret = gf_bs_write_data(ptr->bs, data, dataSize);
559 560614 : if (ret != dataSize) {
560 0 : ptr->curPos = orig;
561 0 : gf_bs_seek(ptr->bs, orig);
562 0 : return GF_IO_ERR;
563 : }
564 560614 : ptr->curPos = gf_bs_get_position(ptr->bs);
565 : #if 0
566 : //flush the stream !!
567 : if (ptr->stream) gf_bs_flush(ptr->bs);
568 : #endif
569 560614 : return GF_OK;
570 : }
571 :
572 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
573 :
574 :
575 : #if 0 //file mapping disabled
576 :
577 : #ifdef WIN32
578 :
579 : #include <windows.h>
580 : #include <winerror.h>
581 :
582 : GF_DataMap *gf_isom_fmo_new(const char *sPath, u8 mode)
583 : {
584 : GF_FileMappingDataMap *tmp;
585 : HANDLE fileH, fileMapH;
586 : #ifdef _WIN32_WCE
587 : unsigned short sWPath[MAX_PATH];
588 : #endif
589 :
590 : //only in read only
591 : if (mode != GF_ISOM_DATA_MAP_READ) return NULL;
592 :
593 : GF_SAFEALLOC(tmp, GF_FileMappingDataMap);
594 : if (!tmp) return NULL;
595 :
596 : tmp->type = GF_ISOM_DATA_FILE_MAPPING;
597 : tmp->mode = mode;
598 : tmp->name = gf_strdup(sPath);
599 :
600 : //
601 : // Open the file
602 : //
603 : #ifdef _WIN32_WCE
604 : //convert to WIDE
605 : CE_CharToWide((char *)sPath, sWPath);
606 :
607 : fileH = CreateFileForMapping(sWPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
608 : (FILE_ATTRIBUTE_READONLY | FILE_FLAG_RANDOM_ACCESS), NULL );
609 : #else
610 : fileH = CreateFile(sPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
611 : (FILE_ATTRIBUTE_READONLY | FILE_FLAG_RANDOM_ACCESS), NULL );
612 : #endif
613 :
614 :
615 : if (fileH == INVALID_HANDLE_VALUE) {
616 : gf_free(tmp->name);
617 : gf_free(tmp);
618 : return NULL;
619 : }
620 :
621 : tmp->file_size = GetFileSize(fileH, NULL);
622 : if (tmp->file_size == 0xFFFFFFFF) {
623 : CloseHandle(fileH);
624 : gf_free(tmp->name);
625 : gf_free(tmp);
626 : return NULL;
627 : }
628 :
629 : //
630 : // Create the mapping
631 : //
632 : fileMapH = CreateFileMapping(fileH, NULL, PAGE_READONLY, 0, 0, NULL);
633 : if (fileMapH == NULL) {
634 : CloseHandle(fileH);
635 : gf_free(tmp->name);
636 : gf_free(tmp);
637 : return NULL;
638 : }
639 :
640 : tmp->byte_map = MapViewOfFile(fileMapH, FILE_MAP_READ, 0, 0, 0);
641 : if (tmp->byte_map == NULL) {
642 : CloseHandle(fileMapH);
643 : CloseHandle(fileH);
644 : gf_free(tmp->name);
645 : gf_free(tmp);
646 : return NULL;
647 : }
648 :
649 : CloseHandle(fileH);
650 : CloseHandle(fileMapH);
651 :
652 : //finaly open our bitstream (from buffer)
653 : tmp->bs = gf_bs_new(tmp->byte_map, tmp->file_size, GF_BITSTREAM_READ);
654 : return (GF_DataMap *)tmp;
655 : }
656 :
657 : void gf_isom_fmo_del(GF_FileMappingDataMap *ptr)
658 : {
659 : if (!ptr || (ptr->type != GF_ISOM_DATA_FILE_MAPPING)) return;
660 :
661 : if (ptr->bs) gf_bs_del(ptr->bs);
662 : if (ptr->byte_map) UnmapViewOfFile(ptr->byte_map);
663 : gf_free(ptr->name);
664 : gf_free(ptr);
665 : }
666 :
667 :
668 : u32 gf_isom_fmo_get_data(GF_FileMappingDataMap *ptr, u8 *buffer, u32 bufferLength, u64 fileOffset)
669 : {
670 : //can we seek till that point ???
671 : if (fileOffset > ptr->file_size) return 0;
672 :
673 : //we do only read operations, so trivial
674 : memcpy(buffer, ptr->byte_map + fileOffset, bufferLength);
675 : return bufferLength;
676 : }
677 :
678 : #else
679 :
680 : GF_DataMap *gf_isom_fmo_new(const char *sPath, u8 mode)
681 : {
682 : return gf_isom_fdm_new(sPath, mode);
683 : }
684 :
685 : void gf_isom_fmo_del(GF_FileMappingDataMap *ptr)
686 : {
687 : gf_isom_fdm_del((GF_FileDataMap *)ptr);
688 : }
689 :
690 : u32 gf_isom_fmo_get_data(GF_FileMappingDataMap *ptr, u8 *buffer, u32 bufferLength, u64 fileOffset)
691 : {
692 : return gf_isom_fdm_get_data((GF_FileDataMap *)ptr, buffer, bufferLength, fileOffset);
693 : }
694 :
695 : #endif //win32
696 : #endif //file mapping disabled
697 :
698 : #endif /*GPAC_DISABLE_ISOM*/
|