4 * Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
5 * Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6 * Copyright 2002 Andriy Palamarchuk
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 static BOOL
Append(LPWSTR
*ppszText
, DWORD
*pdwTextLen
, LPCWSTR pszAppendText
, DWORD dwAppendLen
)
33 pszNewText
= (LPWSTR
) HeapReAlloc(GetProcessHeap(), 0, *ppszText
, (*pdwTextLen
+ dwAppendLen
) * sizeof(WCHAR
));
37 pszNewText
= (LPWSTR
) HeapAlloc(GetProcessHeap(), 0, dwAppendLen
* sizeof(WCHAR
));
43 memcpy(pszNewText
+ *pdwTextLen
, pszAppendText
, dwAppendLen
* sizeof(WCHAR
));
44 *ppszText
= pszNewText
;
45 *pdwTextLen
+= dwAppendLen
;
50 BOOL
ReadText(HANDLE hFile
, LPWSTR
*ppszText
, DWORD
*pdwTextLen
, int *piEncoding
, int *piEoln
)
55 LPWSTR pszAllocText
= NULL
;
58 BOOL bSuccess
= FALSE
;
60 int iEncoding
= ENCODING_ANSI
;
62 WCHAR szCrlf
[2] = { '\r', '\n' };
63 DWORD adwEolnCount
[3] = { 0, 0, 0 };
68 dwSize
= GetFileSize(hFile
, NULL
);
69 if (dwSize
== INVALID_FILE_SIZE
)
72 pBytes
= HeapAlloc(GetProcessHeap(), 0, dwSize
+ 2);
76 if (!ReadFile(hFile
, pBytes
, dwSize
, &dwSize
, NULL
))
80 /* Make sure that there is a NUL character at the end, in any encoding */
81 pBytes
[dwSize
+ 0] = '\0';
82 pBytes
[dwSize
+ 1] = '\0';
84 /* Look for Byte Order Marks */
85 if ((dwSize
>= 2) && (pBytes
[0] == 0xFF) && (pBytes
[1] == 0xFE))
87 iEncoding
= ENCODING_UNICODE
;
90 else if ((dwSize
>= 2) && (pBytes
[0] == 0xFE) && (pBytes
[1] == 0xFF))
92 iEncoding
= ENCODING_UNICODE_BE
;
95 else if ((dwSize
>= 3) && (pBytes
[0] == 0xEF) && (pBytes
[1] == 0xBB) && (pBytes
[2] == 0xBF))
97 iEncoding
= ENCODING_UTF8
;
103 case ENCODING_UNICODE_BE
:
104 for (i
= dwPos
; i
< dwSize
-1; i
+= 2)
107 pBytes
[i
+0] = pBytes
[i
+1];
112 case ENCODING_UNICODE
:
113 pszText
= (LPCWSTR
) &pBytes
[dwPos
];
114 dwCharCount
= (dwSize
- dwPos
) / sizeof(WCHAR
);
119 if (iEncoding
== ENCODING_ANSI
)
121 else if (iEncoding
== ENCODING_UTF8
)
126 if ((dwSize
- dwPos
) > 0)
128 dwCharCount
= MultiByteToWideChar(iCodePage
, 0, (LPCSTR
)&pBytes
[dwPos
], dwSize
- dwPos
, NULL
, 0);
129 if (dwCharCount
== 0)
134 /* special case for files with no characters (other than BOMs) */
138 pszAllocText
= (LPWSTR
) HeapAlloc(GetProcessHeap(), 0, (dwCharCount
+ 1) * sizeof(WCHAR
));
142 if ((dwSize
- dwPos
) > 0)
144 if (!MultiByteToWideChar(iCodePage
, 0, (LPCSTR
)&pBytes
[dwPos
], dwSize
- dwPos
, pszAllocText
, dwCharCount
))
148 pszAllocText
[dwCharCount
] = '\0';
149 pszText
= pszAllocText
;
154 for (i
= 0; i
< dwCharCount
; i
++)
159 if ((i
< dwCharCount
-1) && (pszText
[i
+1] == '\n'))
162 adwEolnCount
[EOLN_CRLF
]++;
168 if (!Append(ppszText
, pdwTextLen
, &pszText
[dwPos
], i
- dwPos
))
170 if (!Append(ppszText
, pdwTextLen
, szCrlf
, sizeof(szCrlf
) / sizeof(szCrlf
[0])))
174 if (pszText
[i
] == '\r')
175 adwEolnCount
[EOLN_CR
]++;
177 adwEolnCount
[EOLN_LF
]++;
182 if (!*ppszText
&& (pszText
== pszAllocText
))
184 /* special case; don't need to reallocate */
185 *ppszText
= pszAllocText
;
186 *pdwTextLen
= dwCharCount
;
191 /* append last remaining text */
192 if (!Append(ppszText
, pdwTextLen
, &pszText
[dwPos
], i
- dwPos
+ 1))
196 /* chose which eoln to use */
198 if (adwEolnCount
[EOLN_LF
] > adwEolnCount
[*piEoln
])
200 if (adwEolnCount
[EOLN_CR
] > adwEolnCount
[*piEoln
])
202 *piEncoding
= iEncoding
;
208 HeapFree(GetProcessHeap(), 0, pBytes
);
210 HeapFree(GetProcessHeap(), 0, pszAllocText
);
212 if (!bSuccess
&& *ppszText
)
214 HeapFree(GetProcessHeap(), 0, *ppszText
);
221 static BOOL
WriteEncodedText(HANDLE hFile
, LPCWSTR pszText
, DWORD dwTextLen
, int iEncoding
)
223 LPBYTE pBytes
= NULL
;
224 LPBYTE pAllocBuffer
= NULL
;
230 BOOL bSuccess
= FALSE
;
231 int iBufferSize
, iRequiredBytes
;
234 while(dwPos
< dwTextLen
)
238 case ENCODING_UNICODE
:
239 pBytes
= (LPBYTE
) &pszText
[dwPos
];
240 dwByteCount
= (dwTextLen
- dwPos
) * sizeof(WCHAR
);
244 case ENCODING_UNICODE_BE
:
245 dwByteCount
= (dwTextLen
- dwPos
) * sizeof(WCHAR
);
246 if (dwByteCount
> sizeof(buffer
))
247 dwByteCount
= sizeof(buffer
);
249 memcpy(buffer
, &pszText
[dwPos
], dwByteCount
);
250 for (i
= 0; i
< dwByteCount
; i
+= 2)
253 buffer
[i
+0] = buffer
[i
+1];
256 pBytes
= (LPBYTE
) &buffer
[dwPos
];
257 dwPos
+= dwByteCount
/ sizeof(WCHAR
);
262 if (iEncoding
== ENCODING_ANSI
)
264 else if (iEncoding
== ENCODING_UTF8
)
269 iRequiredBytes
= WideCharToMultiByte(iCodePage
, 0, &pszText
[dwPos
], dwTextLen
- dwPos
, NULL
, 0, NULL
, NULL
);
270 if (iRequiredBytes
<= 0)
274 else if (iRequiredBytes
< sizeof(buffer
))
277 iBufferSize
= sizeof(buffer
);
281 pAllocBuffer
= (LPBYTE
) HeapAlloc(GetProcessHeap(), 0, iRequiredBytes
);
284 pBytes
= pAllocBuffer
;
285 iBufferSize
= iRequiredBytes
;
288 dwByteCount
= WideCharToMultiByte(iCodePage
, 0, &pszText
[dwPos
], dwTextLen
- dwPos
, (LPSTR
) pBytes
, iBufferSize
, NULL
, NULL
);
299 if (!WriteFile(hFile
, pBytes
, dwByteCount
, &dwDummy
, NULL
))
302 /* free the buffer, if we have allocated one */
305 HeapFree(GetProcessHeap(), 0, pAllocBuffer
);
313 HeapFree(GetProcessHeap(), 0, pAllocBuffer
);
317 BOOL
WriteText(HANDLE hFile
, LPCWSTR pszText
, DWORD dwTextLen
, int iEncoding
, int iEoln
)
322 LPBYTE pbEoln
= NULL
;
323 DWORD dwDummy
, dwPos
, dwNext
, dwEolnSize
= 0;
325 /* Write the proper byte order marks if not ANSI */
326 if (iEncoding
!= ENCODING_ANSI
)
329 if (!WriteEncodedText(hFile
, &wcBom
, 1, iEncoding
))
333 /* Identify the proper eoln to use */
339 dwEolnSize
= sizeof(bEoln
);
344 dwEolnSize
= sizeof(bEoln
);
348 /* If we have an eoln, make sure it is of the proper encoding */
349 if (pbEoln
&& ((iEncoding
== ENCODING_UNICODE
) || (iEncoding
== ENCODING_UNICODE_BE
)))
352 pbEoln
= (LPBYTE
) &wcEoln
;
353 dwEolnSize
= sizeof(wcEoln
);
358 while(dwPos
< dwTextLen
)
362 /* Find the next eoln */
364 while(dwNext
< dwTextLen
-1)
366 if ((pszText
[dwNext
] == '\r') && (pszText
[dwNext
+1] == '\n'))
373 /* No eoln conversion is necessary */
377 if (!WriteEncodedText(hFile
, &pszText
[dwPos
], dwNext
- dwPos
, iEncoding
))
381 /* are we at an eoln? */
382 while ((dwPos
< dwTextLen
-1) &&
383 ((pszText
[dwPos
] == '\r') && (pszText
[dwPos
+1] == '\n')))
385 if (!WriteFile(hFile
, pbEoln
, dwEolnSize
, &dwDummy
, NULL
))
390 while(dwPos
< dwTextLen
);