1 /******************************************************************************
2  * Project:  PROJ.4
3  * Purpose:  Implementation of the pj_ctx_* file api, and the default stdio
4  *           based implementation.
5  * Author:   Frank Warmerdam, warmerdam@pobox.com
6  *
7  ******************************************************************************
8  * Copyright (c) 2013, Frank Warmerdam
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  *****************************************************************************/
28 
29 #include <projects.h>
30 #include <string.h>
31 
32 static PAFile pj_stdio_fopen(projCtx ctx, const char *filename,
33                              const char *access);
34 static size_t pj_stdio_fread(void *buffer, size_t size, size_t nmemb,
35                              PAFile file);
36 static int pj_stdio_fseek(PAFile file, long offset, int whence);
37 static long pj_stdio_ftell(PAFile file);
38 static void pj_stdio_fclose(PAFile file);
39 
40 static projFileAPI default_fileapi = {
41     pj_stdio_fopen,
42     pj_stdio_fread,
43     pj_stdio_fseek,
44     pj_stdio_ftell,
45     pj_stdio_fclose
46 };
47 
48 typedef struct {
49     projCtx ctx;
50     FILE *fp;
51 } stdio_pafile;
52 
53 /************************************************************************/
54 /*                       pj_get_default_fileapi()                       */
55 /************************************************************************/
56 
pj_get_default_fileapi()57 projFileAPI *pj_get_default_fileapi()
58 {
59     return &default_fileapi;
60 }
61 
62 /************************************************************************/
63 /*                           pj_stdio_fopen()                           */
64 /************************************************************************/
65 
pj_stdio_fopen(projCtx ctx,const char * filename,const char * access)66 static PAFile pj_stdio_fopen(projCtx ctx, const char *filename,
67                              const char *access)
68 {
69     stdio_pafile *pafile;
70     FILE *fp;
71 
72     fp = fopen(filename, access);
73     if (fp == NULL)
74     {
75         return NULL;
76     }
77 
78     pafile = (stdio_pafile *) malloc(sizeof(stdio_pafile));
79     pafile->fp = fp;
80     pafile->ctx = ctx;
81     return (PAFile) pafile;
82 }
83 
84 /************************************************************************/
85 /*                           pj_stdio_fread()                           */
86 /************************************************************************/
87 
pj_stdio_fread(void * buffer,size_t size,size_t nmemb,PAFile file)88 static size_t pj_stdio_fread(void *buffer, size_t size, size_t nmemb,
89                              PAFile file)
90 {
91     stdio_pafile *pafile = (stdio_pafile *) file;
92     return fread(buffer, size, nmemb, pafile->fp);
93 }
94 
95 /************************************************************************/
96 /*                           pj_stdio_fseek()                           */
97 /************************************************************************/
pj_stdio_fseek(PAFile file,long offset,int whence)98 static int pj_stdio_fseek(PAFile file, long offset, int whence)
99 {
100     stdio_pafile *pafile = (stdio_pafile *) file;
101     return fseek(pafile->fp, offset, whence);
102 }
103 
104 /************************************************************************/
105 /*                           pj_stdio_ftell()                           */
106 /************************************************************************/
pj_stdio_ftell(PAFile file)107 static long pj_stdio_ftell(PAFile file)
108 {
109     stdio_pafile *pafile = (stdio_pafile *) file;
110     return ftell(pafile->fp);
111 }
112 
113 /************************************************************************/
114 /*                          pj_stdio_fclose()                           */
115 /************************************************************************/
pj_stdio_fclose(PAFile file)116 static void pj_stdio_fclose(PAFile file)
117 {
118     stdio_pafile *pafile = (stdio_pafile *) file;
119     fclose(pafile->fp);
120     free(pafile);
121 }
122 
123 /************************************************************************/
124 /*                            pj_ctx_fopen()                            */
125 /*                                                                      */
126 /*      Open a file using the provided file io hooks.                   */
127 /************************************************************************/
128 
pj_ctx_fopen(projCtx ctx,const char * filename,const char * access)129 PAFile pj_ctx_fopen(projCtx ctx, const char *filename, const char *access)
130 {
131     return ctx->fileapi->FOpen(ctx, filename, access);
132 }
133 
134 /************************************************************************/
135 /*                            pj_ctx_fread()                            */
136 /************************************************************************/
pj_ctx_fread(projCtx ctx,void * buffer,size_t size,size_t nmemb,PAFile file)137 size_t pj_ctx_fread(projCtx ctx, void *buffer, size_t size, size_t nmemb, PAFile file)
138 {
139     return ctx->fileapi->FRead(buffer, size, nmemb, file);
140 }
141 
142 /************************************************************************/
143 /*                            pj_ctx_fseek()                            */
144 /************************************************************************/
pj_ctx_fseek(projCtx ctx,PAFile file,long offset,int whence)145 int    pj_ctx_fseek(projCtx ctx, PAFile file, long offset, int whence)
146 {
147     return ctx->fileapi->FSeek(file, offset, whence);
148 }
149 
150 /************************************************************************/
151 /*                            pj_ctx_ftell()                            */
152 /************************************************************************/
pj_ctx_ftell(projCtx ctx,PAFile file)153 long   pj_ctx_ftell(projCtx ctx, PAFile file)
154 {
155     return ctx->fileapi->FTell(file);
156 }
157 
158 /************************************************************************/
159 /*                           pj_ctx_fclose()                            */
160 /************************************************************************/
pj_ctx_fclose(projCtx ctx,PAFile file)161 void   pj_ctx_fclose(projCtx ctx, PAFile file)
162 {
163     ctx->fileapi->FClose(file);
164 }
165 
166 /************************************************************************/
167 /*                            pj_ctx_fgets()                            */
168 /*                                                                      */
169 /*      A not very optimal implementation of fgets on top of            */
170 /*      fread().  If we end up using this a lot more care should be     */
171 /*      taken.                                                          */
172 /************************************************************************/
173 
pj_ctx_fgets(projCtx ctx,char * line,int size,PAFile file)174 char *pj_ctx_fgets(projCtx ctx, char *line, int size, PAFile file)
175 {
176     long start = pj_ctx_ftell(ctx, file);
177     size_t bytes_read;
178     int i;
179 
180     line[size-1] = '\0';
181     bytes_read = pj_ctx_fread(ctx, line, 1, size-1, file);
182     if(bytes_read == 0)
183         return NULL;
184     if(bytes_read < (size_t)size)
185     {
186         line[bytes_read] = '\0';
187     }
188 
189     for( i = 0; i < size-2; i++)
190     {
191         if (line[i] == '\n')
192         {
193             line[i+1] = '\0';
194             pj_ctx_fseek(ctx, file, start + i + 1, SEEK_SET);
195             break;
196         }
197     }
198     return line;
199 }
200