1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "util/CompleteFile.h"
8 
9 #include <cstring>     // std::strcmp
10 #include <stdio.h>     // FILE, fileno, fopen, getc, getc_unlocked, _getc_nolock
11 #include <sys/stat.h>  // stat, fstat
12 
13 #include "jsapi.h"        // JS_ReportErrorNumberLatin1
14 #include "jsfriendapi.h"  // js::GetErrorMessage, JSMSG_CANT_OPEN
15 
ReadCompleteFile(JSContext * cx,FILE * fp,FileContents & buffer)16 bool js::ReadCompleteFile(JSContext* cx, FILE* fp, FileContents& buffer) {
17   /* Get the complete length of the file, if possible. */
18   struct stat st;
19   int ok = fstat(fileno(fp), &st);
20   if (ok != 0) {
21     return false;
22   }
23   if (st.st_size > 0) {
24     if (!buffer.reserve(st.st_size)) {
25       return false;
26     }
27   }
28 
29   /* Use the fastest available getc. */
30   auto fast_getc =
31 #if defined(HAVE_GETC_UNLOCKED)
32       getc_unlocked
33 #elif defined(HAVE__GETC_NOLOCK)
34       _getc_nolock
35 #else
36       getc
37 #endif
38       ;
39 
40   // Read in the whole file. Note that we can't assume the data's length
41   // is actually st.st_size, because 1) some files lie about their size
42   // (/dev/zero and /dev/random), and 2) reading files in text mode on
43   // Windows collapses "\r\n" pairs to single \n characters.
44   for (;;) {
45     int c = fast_getc(fp);
46     if (c == EOF) {
47       break;
48     }
49     if (!buffer.append(c)) {
50       return false;
51     }
52   }
53 
54   return true;
55 }
56 
57 /*
58  * Open a source file for reading. Supports "-" and nullptr to mean stdin. The
59  * return value must be fclosed unless it is stdin.
60  */
open(JSContext * cx,const char * filename)61 bool js::AutoFile::open(JSContext* cx, const char* filename) {
62   if (!filename || std::strcmp(filename, "-") == 0) {
63     fp_ = stdin;
64   } else {
65     fp_ = fopen(filename, "r");
66     if (!fp_) {
67       /*
68        * Use Latin1 variant here because the encoding of filename is
69        * platform dependent.
70        */
71       JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_CANT_OPEN,
72                                  filename, "No such file or directory");
73       return false;
74     }
75   }
76   return true;
77 }
78