1 /*---------------------------------------------------------------------------*
2 * PFileImpl.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20 #include "passert.h"
21 #include "pendian.h"
22 #include "PFileImpl.h"
23 #include "PFileSystem.h"
24 #include "plog.h"
25 #include "pmemory.h"
26 #include "pstdio.h"
27 #include "ptypes.h"
28
29 #define MTAG NULL
30
31
32 /**
33 * Initializes variables declared in the superinterface.
34 */
PFileCreateImpl(PFile * self,const LCHAR * filename,ESR_BOOL isLittleEndian)35 ESR_ReturnCode PFileCreateImpl(PFile* self, const LCHAR* filename, ESR_BOOL isLittleEndian)
36 {
37 PFileImpl* impl = (PFileImpl*) self;
38 ESR_ReturnCode rc;
39 #ifdef USE_THREAD
40 ESR_BOOL threadingEnabled;
41 #endif
42
43 #ifdef USE_THREAD
44 impl->lock = NULL;
45 #endif
46 impl->littleEndian = isLittleEndian;
47
48 impl->Interface.destroy = &PFileDestroyImpl;
49 impl->Interface.getFilename = &PFileGetFilenameImpl;
50 impl->Interface.vfprintf = &PFileVfprintfImpl;
51 impl->filename = MALLOC(sizeof(LCHAR) * (LSTRLEN(filename) + 1), MTAG);
52
53 if (impl->filename == NULL)
54 {
55 rc = ESR_OUT_OF_MEMORY;
56 PLogError(ESR_rc2str(rc));
57 goto CLEANUP;
58 }
59 LSTRCPY(impl->filename, filename);
60
61 #ifdef USE_THREAD
62 rc = PtrdIsEnabled(&threadingEnabled);
63 if (rc != ESR_SUCCESS)
64 {
65 pfprintf(PSTDERR, L("[%s:%d] PtrdIsEnabled failed with %s\n"), __FILE__, __LINE__, ESR_rc2str(rc));
66 goto CLEANUP;
67 }
68 if (threadingEnabled)
69 {
70 rc = PtrdMonitorCreate(&impl->lock);
71 if (rc != ESR_SUCCESS)
72 goto CLEANUP;
73 }
74 #endif
75 return ESR_SUCCESS;
76 CLEANUP:
77 self->destroy(self);
78 return rc;
79 }
80
81
82 #ifdef USE_THREAD
83 #define LOCK_MUTEX(rc, impl) \
84 if (impl->lock != NULL) \
85 CHKLOG(rc, PtrdMonitorLock(impl->lock));
86 #else
87 #define LOCK_MUTEX(rc, impl)
88 #endif
89
90
91 #ifdef USE_THREAD
92 #define CLEANUP_AND_RETURN(rc, impl) \
93 if (impl->lock!=NULL) \
94 CHKLOG(rc, PtrdMonitorUnlock(impl->lock)); \
95 return ESR_SUCCESS; \
96 CLEANUP: \
97 if (impl->lock!=NULL) \
98 PtrdMonitorUnlock(impl->lock); \
99 return rc;
100 #else
101 #define CLEANUP_AND_RETURN(rc, impl) \
102 return ESR_SUCCESS; \
103 CLEANUP: \
104 return rc;
105 #endif
106
107
PFileDestroyImpl(PFile * self)108 ESR_ReturnCode PFileDestroyImpl(PFile* self)
109 {
110 PFileImpl* impl = (PFileImpl*) self;
111 ESR_ReturnCode rc;
112 ESR_BOOL isOpen;
113
114 LOCK_MUTEX(rc, impl);
115 CHKLOG(rc, self->isOpen(self, &isOpen));
116 if (isOpen)
117 CHKLOG(rc, self->close(self));
118 if (impl->filename)
119 {
120 FREE(impl->filename);
121 impl->filename = NULL;
122 }
123 #ifdef USE_THREAD
124 if (impl->lock != NULL)
125 {
126 PtrdMonitorUnlock(impl->lock);
127 rc = PtrdMonitorDestroy(impl->lock);
128 if (rc != ESR_SUCCESS)
129 goto CLEANUP;
130 }
131 #endif
132 return ESR_SUCCESS;
133 CLEANUP:
134 #ifdef USE_THREAD
135 if (impl->lock != NULL)
136 PtrdMonitorUnlock(impl->lock);
137 #endif
138 return rc;
139 }
140
PFileGetFilenameImpl(PFile * self,LCHAR * filename,size_t * len)141 ESR_ReturnCode PFileGetFilenameImpl(PFile* self, LCHAR* filename, size_t* len)
142 {
143 PFileImpl* impl = (PFileImpl*) self;
144 ESR_ReturnCode rc;
145
146 if (self == NULL || len == NULL)
147 {
148 PLogError(L("ESR_INVALID_ARGUMENT"));
149 return ESR_INVALID_ARGUMENT;
150 }
151 LOCK_MUTEX(rc, impl);
152 if (LSTRLEN(impl->filename) + 1 > *len)
153 {
154 *len = LSTRLEN(impl->filename) + 1;
155 rc = ESR_BUFFER_OVERFLOW;
156 goto CLEANUP;
157 }
158 LSTRCPY(filename, impl->filename);
159 CLEANUP_AND_RETURN(rc, impl);
160 }
161
PFileVfprintfImpl(PFile * self,int * result,const LCHAR * format,va_list args)162 ESR_ReturnCode PFileVfprintfImpl(PFile* self, int* result, const LCHAR* format, va_list args)
163 {
164 ESR_ReturnCode rc;
165 ESR_BOOL isOpen;
166 #define BUFFER_SIZE 5120
167 static LCHAR buffer[BUFFER_SIZE];
168 size_t len;
169
170 if (self == NULL)
171 {
172 PLogError(L("ESR_INVALID_ARGUMENT"));
173 return ESR_INVALID_ARGUMENT;
174 }
175
176 CHKLOG(rc, self->isOpen(self, &isOpen));
177 if (!isOpen)
178 {
179 rc = ESR_OPEN_ERROR;
180 PLogError(L("%s: cannot operate on closed file"), ESR_rc2str(rc));
181 goto CLEANUP;
182 }
183
184 /*
185 * fprintf() is computationally expensive, so we compute its output without grabbing a lock
186 * and only lock while actually writing the results into the file.
187 */
188 if (result != NULL)
189 *result = vsprintf(buffer, format, args);
190 else
191 vsprintf(buffer, format, args);
192 len = LSTRLEN(buffer);
193 passert(len < BUFFER_SIZE);
194
195 CHKLOG(rc, self->write(self, buffer, sizeof(LCHAR), &len));
196 return ESR_SUCCESS;
197 CLEANUP:
198 return rc;
199 }
200