Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.desktop/share/native/libharfbuzz/hb-blob.cc
66644 views
1
/*
2
* Copyright © 2009 Red Hat, Inc.
3
* Copyright © 2018 Ebrahim Byagowi
4
*
5
* This is part of HarfBuzz, a text shaping library.
6
*
7
* Permission is hereby granted, without written agreement and without
8
* license or royalty fees, to use, copy, modify, and distribute this
9
* software and its documentation for any purpose, provided that the
10
* above copyright notice and the following two paragraphs appear in
11
* all copies of this software.
12
*
13
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17
* DAMAGE.
18
*
19
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
*
25
* Red Hat Author(s): Behdad Esfahbod
26
*/
27
28
#include "hb.hh"
29
#include "hb-blob.hh"
30
31
#ifdef HAVE_SYS_MMAN_H
32
#ifdef HAVE_UNISTD_H
33
#include <unistd.h>
34
#endif /* HAVE_UNISTD_H */
35
#include <sys/mman.h>
36
#endif /* HAVE_SYS_MMAN_H */
37
38
39
/**
40
* SECTION: hb-blob
41
* @title: hb-blob
42
* @short_description: Binary data containers
43
* @include: hb.h
44
*
45
* Blobs wrap a chunk of binary data to handle lifecycle management of data
46
* while it is passed between client and HarfBuzz. Blobs are primarily used
47
* to create font faces, but also to access font face tables, as well as
48
* pass around other binary data.
49
**/
50
51
52
/**
53
* hb_blob_create: (skip)
54
* @data: Pointer to blob data.
55
* @length: Length of @data in bytes.
56
* @mode: Memory mode for @data.
57
* @user_data: Data parameter to pass to @destroy.
58
* @destroy: (nullable): Callback to call when @data is not needed anymore.
59
*
60
* Creates a new "blob" object wrapping @data. The @mode parameter is used
61
* to negotiate ownership and lifecycle of @data.
62
*
63
* Return value: New blob, or the empty blob if something failed or if @length is
64
* zero. Destroy with hb_blob_destroy().
65
*
66
* Since: 0.9.2
67
**/
68
hb_blob_t *
69
hb_blob_create (const char *data,
70
unsigned int length,
71
hb_memory_mode_t mode,
72
void *user_data,
73
hb_destroy_func_t destroy)
74
{
75
if (!length)
76
{
77
if (destroy)
78
destroy (user_data);
79
return hb_blob_get_empty ();
80
}
81
82
hb_blob_t *blob = hb_blob_create_or_fail (data, length, mode,
83
user_data, destroy);
84
return likely (blob) ? blob : hb_blob_get_empty ();
85
}
86
87
/**
88
* hb_blob_create_or_fail: (skip)
89
* @data: Pointer to blob data.
90
* @length: Length of @data in bytes.
91
* @mode: Memory mode for @data.
92
* @user_data: Data parameter to pass to @destroy.
93
* @destroy: (nullable): Callback to call when @data is not needed anymore.
94
*
95
* Creates a new "blob" object wrapping @data. The @mode parameter is used
96
* to negotiate ownership and lifecycle of @data.
97
*
98
* Note that this function returns a freshly-allocated empty blob even if @length
99
* is zero. This is in contrast to hb_blob_create(), which returns the singleton
100
* empty blob (as returned by hb_blob_get_empty()) if @length is zero.
101
*
102
* Return value: New blob, or %NULL if failed. Destroy with hb_blob_destroy().
103
*
104
* Since: 2.8.2
105
**/
106
hb_blob_t *
107
hb_blob_create_or_fail (const char *data,
108
unsigned int length,
109
hb_memory_mode_t mode,
110
void *user_data,
111
hb_destroy_func_t destroy)
112
{
113
hb_blob_t *blob;
114
115
if (length >= 1u << 31 ||
116
!(blob = hb_object_create<hb_blob_t> ()))
117
{
118
if (destroy)
119
destroy (user_data);
120
return nullptr;
121
}
122
123
blob->data = data;
124
blob->length = length;
125
blob->mode = mode;
126
127
blob->user_data = user_data;
128
blob->destroy = destroy;
129
130
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
131
blob->mode = HB_MEMORY_MODE_READONLY;
132
if (!blob->try_make_writable ())
133
{
134
hb_blob_destroy (blob);
135
return nullptr;
136
}
137
}
138
139
return blob;
140
}
141
142
static void
143
_hb_blob_destroy (void *data)
144
{
145
hb_blob_destroy ((hb_blob_t *) data);
146
}
147
148
/**
149
* hb_blob_create_sub_blob:
150
* @parent: Parent blob.
151
* @offset: Start offset of sub-blob within @parent, in bytes.
152
* @length: Length of sub-blob.
153
*
154
* Returns a blob that represents a range of bytes in @parent. The new
155
* blob is always created with #HB_MEMORY_MODE_READONLY, meaning that it
156
* will never modify data in the parent blob. The parent data is not
157
* expected to be modified, and will result in undefined behavior if it
158
* is.
159
*
160
* Makes @parent immutable.
161
*
162
* Return value: New blob, or the empty blob if something failed or if
163
* @length is zero or @offset is beyond the end of @parent's data. Destroy
164
* with hb_blob_destroy().
165
*
166
* Since: 0.9.2
167
**/
168
hb_blob_t *
169
hb_blob_create_sub_blob (hb_blob_t *parent,
170
unsigned int offset,
171
unsigned int length)
172
{
173
hb_blob_t *blob;
174
175
if (!length || !parent || offset >= parent->length)
176
return hb_blob_get_empty ();
177
178
hb_blob_make_immutable (parent);
179
180
blob = hb_blob_create (parent->data + offset,
181
hb_min (length, parent->length - offset),
182
HB_MEMORY_MODE_READONLY,
183
hb_blob_reference (parent),
184
_hb_blob_destroy);
185
186
return blob;
187
}
188
189
/**
190
* hb_blob_copy_writable_or_fail:
191
* @blob: A blob.
192
*
193
* Makes a writable copy of @blob.
194
*
195
* Return value: The new blob, or nullptr if allocation failed
196
*
197
* Since: 1.8.0
198
**/
199
hb_blob_t *
200
hb_blob_copy_writable_or_fail (hb_blob_t *blob)
201
{
202
blob = hb_blob_create (blob->data,
203
blob->length,
204
HB_MEMORY_MODE_DUPLICATE,
205
nullptr,
206
nullptr);
207
208
if (unlikely (blob == hb_blob_get_empty ()))
209
blob = nullptr;
210
211
return blob;
212
}
213
214
/**
215
* hb_blob_get_empty:
216
*
217
* Returns the singleton empty blob.
218
*
219
* See TODO:link object types for more information.
220
*
221
* Return value: (transfer full): The empty blob.
222
*
223
* Since: 0.9.2
224
**/
225
hb_blob_t *
226
hb_blob_get_empty ()
227
{
228
return const_cast<hb_blob_t *> (&Null (hb_blob_t));
229
}
230
231
/**
232
* hb_blob_reference: (skip)
233
* @blob: a blob.
234
*
235
* Increases the reference count on @blob.
236
*
237
* See TODO:link object types for more information.
238
*
239
* Return value: @blob.
240
*
241
* Since: 0.9.2
242
**/
243
hb_blob_t *
244
hb_blob_reference (hb_blob_t *blob)
245
{
246
return hb_object_reference (blob);
247
}
248
249
/**
250
* hb_blob_destroy: (skip)
251
* @blob: a blob.
252
*
253
* Decreases the reference count on @blob, and if it reaches zero, destroys
254
* @blob, freeing all memory, possibly calling the destroy-callback the blob
255
* was created for if it has not been called already.
256
*
257
* See TODO:link object types for more information.
258
*
259
* Since: 0.9.2
260
**/
261
void
262
hb_blob_destroy (hb_blob_t *blob)
263
{
264
if (!hb_object_destroy (blob)) return;
265
266
blob->fini_shallow ();
267
268
hb_free (blob);
269
}
270
271
/**
272
* hb_blob_set_user_data: (skip)
273
* @blob: An #hb_blob_t
274
* @key: The user-data key to set
275
* @data: A pointer to the user data to set
276
* @destroy: (nullable): A callback to call when @data is not needed anymore
277
* @replace: Whether to replace an existing data with the same key
278
*
279
* Attaches a user-data key/data pair to the specified blob.
280
*
281
* Return value: %true if success, %false otherwise
282
*
283
* Since: 0.9.2
284
**/
285
hb_bool_t
286
hb_blob_set_user_data (hb_blob_t *blob,
287
hb_user_data_key_t *key,
288
void * data,
289
hb_destroy_func_t destroy,
290
hb_bool_t replace)
291
{
292
return hb_object_set_user_data (blob, key, data, destroy, replace);
293
}
294
295
/**
296
* hb_blob_get_user_data: (skip)
297
* @blob: a blob
298
* @key: The user-data key to query
299
*
300
* Fetches the user data associated with the specified key,
301
* attached to the specified font-functions structure.
302
*
303
* Return value: (transfer none): A pointer to the user data
304
*
305
* Since: 0.9.2
306
**/
307
void *
308
hb_blob_get_user_data (hb_blob_t *blob,
309
hb_user_data_key_t *key)
310
{
311
return hb_object_get_user_data (blob, key);
312
}
313
314
315
/**
316
* hb_blob_make_immutable:
317
* @blob: a blob
318
*
319
* Makes a blob immutable.
320
*
321
* Since: 0.9.2
322
**/
323
void
324
hb_blob_make_immutable (hb_blob_t *blob)
325
{
326
if (hb_object_is_immutable (blob))
327
return;
328
329
hb_object_make_immutable (blob);
330
}
331
332
/**
333
* hb_blob_is_immutable:
334
* @blob: a blob.
335
*
336
* Tests whether a blob is immutable.
337
*
338
* Return value: %true if @blob is immutable, %false otherwise
339
*
340
* Since: 0.9.2
341
**/
342
hb_bool_t
343
hb_blob_is_immutable (hb_blob_t *blob)
344
{
345
return hb_object_is_immutable (blob);
346
}
347
348
349
/**
350
* hb_blob_get_length:
351
* @blob: a blob.
352
*
353
* Fetches the length of a blob's data.
354
*
355
* Return value: the length of @blob data in bytes.
356
*
357
* Since: 0.9.2
358
**/
359
unsigned int
360
hb_blob_get_length (hb_blob_t *blob)
361
{
362
return blob->length;
363
}
364
365
/**
366
* hb_blob_get_data:
367
* @blob: a blob.
368
* @length: (out): The length in bytes of the data retrieved
369
*
370
* Fetches the data from a blob.
371
*
372
* Returns: (nullable) (transfer none) (array length=length): the byte data of @blob.
373
*
374
* Since: 0.9.2
375
**/
376
const char *
377
hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
378
{
379
if (length)
380
*length = blob->length;
381
382
return blob->data;
383
}
384
385
/**
386
* hb_blob_get_data_writable:
387
* @blob: a blob.
388
* @length: (out): output length of the writable data.
389
*
390
* Tries to make blob data writable (possibly copying it) and
391
* return pointer to data.
392
*
393
* Fails if blob has been made immutable, or if memory allocation
394
* fails.
395
*
396
* Returns: (transfer none) (array length=length): Writable blob data,
397
* or %NULL if failed.
398
*
399
* Since: 0.9.2
400
**/
401
char *
402
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
403
{
404
if (hb_object_is_immutable (blob) ||
405
!blob->try_make_writable ())
406
{
407
if (length) *length = 0;
408
return nullptr;
409
}
410
411
if (length) *length = blob->length;
412
return const_cast<char *> (blob->data);
413
}
414
415
416
bool
417
hb_blob_t::try_make_writable_inplace_unix ()
418
{
419
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
420
uintptr_t pagesize = -1, mask, length;
421
const char *addr;
422
423
#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
424
pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
425
#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
426
pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
427
#elif defined(HAVE_GETPAGESIZE)
428
pagesize = (uintptr_t) getpagesize ();
429
#endif
430
431
if ((uintptr_t) -1L == pagesize) {
432
DEBUG_MSG_FUNC (BLOB, this, "failed to get pagesize: %s", strerror (errno));
433
return false;
434
}
435
DEBUG_MSG_FUNC (BLOB, this, "pagesize is %lu", (unsigned long) pagesize);
436
437
mask = ~(pagesize-1);
438
addr = (const char *) (((uintptr_t) this->data) & mask);
439
length = (const char *) (((uintptr_t) this->data + this->length + pagesize-1) & mask) - addr;
440
DEBUG_MSG_FUNC (BLOB, this,
441
"calling mprotect on [%p..%p] (%lu bytes)",
442
addr, addr+length, (unsigned long) length);
443
if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
444
DEBUG_MSG_FUNC (BLOB, this, "mprotect failed: %s", strerror (errno));
445
return false;
446
}
447
448
this->mode = HB_MEMORY_MODE_WRITABLE;
449
450
DEBUG_MSG_FUNC (BLOB, this,
451
"successfully made [%p..%p] (%lu bytes) writable\n",
452
addr, addr+length, (unsigned long) length);
453
return true;
454
#else
455
return false;
456
#endif
457
}
458
459
bool
460
hb_blob_t::try_make_writable_inplace ()
461
{
462
DEBUG_MSG_FUNC (BLOB, this, "making writable inplace\n");
463
464
if (this->try_make_writable_inplace_unix ())
465
return true;
466
467
DEBUG_MSG_FUNC (BLOB, this, "making writable -> FAILED\n");
468
469
/* Failed to make writable inplace, mark that */
470
this->mode = HB_MEMORY_MODE_READONLY;
471
return false;
472
}
473
474
bool
475
hb_blob_t::try_make_writable ()
476
{
477
if (unlikely (!length))
478
mode = HB_MEMORY_MODE_WRITABLE;
479
480
if (this->mode == HB_MEMORY_MODE_WRITABLE)
481
return true;
482
483
if (this->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && this->try_make_writable_inplace ())
484
return true;
485
486
if (this->mode == HB_MEMORY_MODE_WRITABLE)
487
return true;
488
489
490
DEBUG_MSG_FUNC (BLOB, this, "current data is -> %p\n", this->data);
491
492
char *new_data;
493
494
new_data = (char *) hb_malloc (this->length);
495
if (unlikely (!new_data))
496
return false;
497
498
DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data);
499
500
memcpy (new_data, this->data, this->length);
501
this->destroy_user_data ();
502
this->mode = HB_MEMORY_MODE_WRITABLE;
503
this->data = new_data;
504
this->user_data = new_data;
505
this->destroy = hb_free;
506
507
return true;
508
}
509
510
/*
511
* Mmap
512
*/
513
514
#ifndef HB_NO_OPEN
515
#ifdef HAVE_MMAP
516
# if !defined(HB_NO_RESOURCE_FORK) && defined(__APPLE__)
517
# include <sys/paths.h>
518
# endif
519
# include <sys/types.h>
520
# include <sys/stat.h>
521
# include <fcntl.h>
522
#endif
523
524
#ifdef _WIN32
525
# include <windows.h>
526
#else
527
# ifndef O_BINARY
528
# define O_BINARY 0
529
# endif
530
#endif
531
532
#ifndef MAP_NORESERVE
533
# define MAP_NORESERVE 0
534
#endif
535
536
struct hb_mapped_file_t
537
{
538
char *contents;
539
unsigned long length;
540
#ifdef _WIN32
541
HANDLE mapping;
542
#endif
543
};
544
545
#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP)
546
static void
547
_hb_mapped_file_destroy (void *file_)
548
{
549
hb_mapped_file_t *file = (hb_mapped_file_t *) file_;
550
#ifdef HAVE_MMAP
551
munmap (file->contents, file->length);
552
#elif defined(_WIN32)
553
UnmapViewOfFile (file->contents);
554
CloseHandle (file->mapping);
555
#else
556
assert (0); // If we don't have mmap we shouldn't reach here
557
#endif
558
559
hb_free (file);
560
}
561
#endif
562
563
#ifdef _PATH_RSRCFORKSPEC
564
static int
565
_open_resource_fork (const char *file_name, hb_mapped_file_t *file)
566
{
567
size_t name_len = strlen (file_name);
568
size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC);
569
570
char *rsrc_name = (char *) hb_malloc (len);
571
if (unlikely (!rsrc_name)) return -1;
572
573
strncpy (rsrc_name, file_name, name_len);
574
strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC,
575
sizeof (_PATH_RSRCFORKSPEC));
576
577
int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
578
hb_free (rsrc_name);
579
580
if (fd != -1)
581
{
582
struct stat st;
583
if (fstat (fd, &st) != -1)
584
file->length = (unsigned long) st.st_size;
585
else
586
{
587
close (fd);
588
fd = -1;
589
}
590
}
591
592
return fd;
593
}
594
#endif
595
596
/**
597
* hb_blob_create_from_file:
598
* @file_name: A font filename
599
*
600
* Creates a new blob containing the data from the
601
* specified binary font file.
602
*
603
* Returns: An #hb_blob_t pointer with the content of the file,
604
* or hb_blob_get_empty() if failed.
605
*
606
* Since: 1.7.7
607
**/
608
hb_blob_t *
609
hb_blob_create_from_file (const char *file_name)
610
{
611
hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
612
return likely (blob) ? blob : hb_blob_get_empty ();
613
}
614
615
/**
616
* hb_blob_create_from_file_or_fail:
617
* @file_name: A font filename
618
*
619
* Creates a new blob containing the data from the
620
* specified binary font file.
621
*
622
* Returns: An #hb_blob_t pointer with the content of the file,
623
* or %NULL if failed.
624
*
625
* Since: 2.8.2
626
**/
627
hb_blob_t *
628
hb_blob_create_from_file_or_fail (const char *file_name)
629
{
630
/* Adopted from glib's gmappedfile.c with Matthias Clasen and
631
Allison Lortie permission but changed a lot to suit our need. */
632
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
633
hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t));
634
if (unlikely (!file)) return nullptr;
635
636
int fd = open (file_name, O_RDONLY | O_BINARY, 0);
637
if (unlikely (fd == -1)) goto fail_without_close;
638
639
struct stat st;
640
if (unlikely (fstat (fd, &st) == -1)) goto fail;
641
642
file->length = (unsigned long) st.st_size;
643
644
#ifdef _PATH_RSRCFORKSPEC
645
if (unlikely (file->length == 0))
646
{
647
int rfd = _open_resource_fork (file_name, file);
648
if (rfd != -1)
649
{
650
close (fd);
651
fd = rfd;
652
}
653
}
654
#endif
655
656
file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
657
MAP_PRIVATE | MAP_NORESERVE, fd, 0);
658
659
if (unlikely (file->contents == MAP_FAILED)) goto fail;
660
661
close (fd);
662
663
return hb_blob_create_or_fail (file->contents, file->length,
664
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
665
(hb_destroy_func_t) _hb_mapped_file_destroy);
666
667
fail:
668
close (fd);
669
fail_without_close:
670
hb_free (file);
671
672
#elif defined(_WIN32) && !defined(HB_NO_MMAP)
673
hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t));
674
if (unlikely (!file)) return nullptr;
675
676
HANDLE fd;
677
unsigned int size = strlen (file_name) + 1;
678
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
679
if (unlikely (!wchar_file_name)) goto fail_without_close;
680
mbstowcs (wchar_file_name, file_name, size);
681
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
682
{
683
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
684
ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
685
ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF;
686
ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000;
687
ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000;
688
ceparams.lpSecurityAttributes = nullptr;
689
ceparams.hTemplateFile = nullptr;
690
fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ,
691
OPEN_EXISTING, &ceparams);
692
}
693
#else
694
fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
695
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
696
nullptr);
697
#endif
698
hb_free (wchar_file_name);
699
700
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
701
702
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
703
{
704
LARGE_INTEGER length;
705
GetFileSizeEx (fd, &length);
706
file->length = length.LowPart;
707
file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr);
708
}
709
#else
710
file->length = (unsigned long) GetFileSize (fd, nullptr);
711
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
712
#endif
713
if (unlikely (!file->mapping)) goto fail;
714
715
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
716
file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
717
#else
718
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
719
#endif
720
if (unlikely (!file->contents)) goto fail;
721
722
CloseHandle (fd);
723
return hb_blob_create_or_fail (file->contents, file->length,
724
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
725
(hb_destroy_func_t) _hb_mapped_file_destroy);
726
727
fail:
728
CloseHandle (fd);
729
fail_without_close:
730
hb_free (file);
731
732
#endif
733
734
/* The following tries to read a file without knowing its size beforehand
735
It's used as a fallback for systems without mmap or to read from pipes */
736
unsigned long len = 0, allocated = BUFSIZ * 16;
737
char *data = (char *) hb_malloc (allocated);
738
if (unlikely (!data)) return nullptr;
739
740
FILE *fp = fopen (file_name, "rb");
741
if (unlikely (!fp)) goto fread_fail_without_close;
742
743
while (!feof (fp))
744
{
745
if (allocated - len < BUFSIZ)
746
{
747
allocated *= 2;
748
/* Don't allocate and go more than ~536MB, our mmap reader still
749
can cover files like that but lets limit our fallback reader */
750
if (unlikely (allocated > (2 << 28))) goto fread_fail;
751
char *new_data = (char *) hb_realloc (data, allocated);
752
if (unlikely (!new_data)) goto fread_fail;
753
data = new_data;
754
}
755
756
unsigned long addition = fread (data + len, 1, allocated - len, fp);
757
758
int err = ferror (fp);
759
#ifdef EINTR // armcc doesn't have it
760
if (unlikely (err == EINTR)) continue;
761
#endif
762
if (unlikely (err)) goto fread_fail;
763
764
len += addition;
765
}
766
fclose (fp);
767
768
return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data,
769
(hb_destroy_func_t) hb_free);
770
771
fread_fail:
772
fclose (fp);
773
fread_fail_without_close:
774
hb_free (data);
775
return nullptr;
776
}
777
#endif /* !HB_NO_OPEN */
778
779