1// Copyright (C) 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5*
6*   Copyright (C) 1999-2010, International Business Machines
7*   Corporation and others.  All Rights Reserved.
8*
9*******************************************************************************
10*   file name:  unewdata.c
11*   encoding:   US-ASCII
12*   tab size:   8 (not used)
13*   indentation:4
14*
15*   created on: 1999oct25
16*   created by: Markus W. Scherer
17*/
18
19#include <stdio.h>
20#include "unicode/utypes.h"
21#include "unicode/putil.h"
22#include "unicode/ustring.h"
23#include "cmemory.h"
24#include "cstring.h"
25#include "filestrm.h"
26#include "unicode/udata.h"
27#include "unewdata.h"
28
29struct UNewDataMemory {
30    FileStream *file;
31    uint16_t headerSize;
32    uint8_t magic1, magic2;
33};
34
35U_CAPI UNewDataMemory * U_EXPORT2
36udata_create(const char *dir, const char *type, const char *name,
37             const UDataInfo *pInfo,
38             const char *comment,
39             UErrorCode *pErrorCode) {
40    UNewDataMemory *pData;
41    uint16_t headerSize, commentLength;
42    char filename[512];
43    uint8_t bytes[16];
44    int32_t length;
45
46    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
47        return NULL;
48    } else if(name==NULL || *name==0 || pInfo==NULL) {
49        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
50        return NULL;
51    }
52
53    /* allocate the data structure */
54    pData=(UNewDataMemory *)uprv_malloc(sizeof(UNewDataMemory));
55    if(pData==NULL) {
56        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
57        return NULL;
58    }
59
60    /* Check that the full path won't be too long */
61    length = 0;					/* Start with nothing */
62    if(dir != NULL  && *dir !=0)	/* Add directory length if one was given */
63    {
64    	length += strlen(dir);
65
66    	/* Add 1 if dir doesn't end with path sep */
67        if (dir[strlen(dir) - 1]!= U_FILE_SEP_CHAR) {
68            length++;
69        }
70	}
71    length += strlen(name);		/* Add the filename length */
72
73    if(type != NULL  && *type !=0) { /* Add directory length if  given */
74        length += strlen(type);
75    }
76
77
78     /* LDH buffer Length error check */
79    if(length  > ((int32_t)sizeof(filename) - 1))
80    {
81   	    *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
82   	    uprv_free(pData);
83	    return NULL;
84    }
85
86    /* open the output file */
87    if(dir!=NULL && *dir!=0) { /* if dir has a value, we prepend it to the filename */
88        char *p=filename+strlen(dir);
89        uprv_strcpy(filename, dir);
90        if (*(p-1)!=U_FILE_SEP_CHAR) {
91            *p++=U_FILE_SEP_CHAR;
92            *p=0;
93        }
94    } else { /* otherwise, we'll output to the current dir */
95        filename[0]=0;
96    }
97    uprv_strcat(filename, name);
98    if(type!=NULL && *type!=0) {
99        uprv_strcat(filename, ".");
100        uprv_strcat(filename, type);
101    }
102    pData->file=T_FileStream_open(filename, "wb");
103    if(pData->file==NULL) {
104        uprv_free(pData);
105        *pErrorCode=U_FILE_ACCESS_ERROR;
106        return NULL;
107    }
108
109    /* write the header information */
110    headerSize=(uint16_t)(pInfo->size+4);
111    if(comment!=NULL && *comment!=0) {
112        commentLength=(uint16_t)(uprv_strlen(comment)+1);
113        headerSize+=commentLength;
114    } else {
115        commentLength=0;
116    }
117
118    /* write the size of the header, take padding into account */
119    pData->headerSize=(uint16_t)((headerSize+15)&~0xf);
120    pData->magic1=0xda;
121    pData->magic2=0x27;
122    T_FileStream_write(pData->file, &pData->headerSize, 4);
123
124    /* write the information data */
125    T_FileStream_write(pData->file, pInfo, pInfo->size);
126
127    /* write the comment */
128    if(commentLength>0) {
129        T_FileStream_write(pData->file, comment, commentLength);
130    }
131
132    /* write padding bytes to align the data section to 16 bytes */
133    headerSize&=0xf;
134    if(headerSize!=0) {
135        headerSize=(uint16_t)(16-headerSize);
136        uprv_memset(bytes, 0, headerSize);
137        T_FileStream_write(pData->file, bytes, headerSize);
138    }
139
140    return pData;
141}
142
143U_CAPI uint32_t U_EXPORT2
144udata_finish(UNewDataMemory *pData, UErrorCode *pErrorCode) {
145    uint32_t fileLength=0;
146
147    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
148        return 0;
149    }
150
151    if(pData!=NULL) {
152        if(pData->file!=NULL) {
153            /* fflush(pData->file);*/
154            fileLength=T_FileStream_size(pData->file);
155            if(T_FileStream_error(pData->file)) {
156                *pErrorCode=U_FILE_ACCESS_ERROR;
157            } else {
158                fileLength-=pData->headerSize;
159            }
160            T_FileStream_close(pData->file);
161        }
162        uprv_free(pData);
163    }
164
165    return fileLength;
166}
167
168/* dummy UDataInfo cf. udata.h */
169static const UDataInfo dummyDataInfo = {
170    sizeof(UDataInfo),
171    0,
172
173    U_IS_BIG_ENDIAN,
174    U_CHARSET_FAMILY,
175    U_SIZEOF_UCHAR,
176    0,
177
178    { 0, 0, 0, 0 },                 /* dummy dataFormat */
179    { 0, 0, 0, 0 },                 /* dummy formatVersion */
180    { 0, 0, 0, 0 }                  /* dummy dataVersion */
181};
182
183U_CAPI void U_EXPORT2
184udata_createDummy(const char *dir, const char *type, const char *name, UErrorCode *pErrorCode) {
185    if(U_SUCCESS(*pErrorCode)) {
186        udata_finish(udata_create(dir, type, name, &dummyDataInfo, NULL, pErrorCode), pErrorCode);
187        if(U_FAILURE(*pErrorCode)) {
188            fprintf(stderr, "error %s writing dummy data file %s" U_FILE_SEP_STRING "%s.%s\n",
189                    u_errorName(*pErrorCode), dir, name, type);
190            exit(*pErrorCode);
191        }
192    }
193}
194
195U_CAPI void U_EXPORT2
196udata_write8(UNewDataMemory *pData, uint8_t byte) {
197    if(pData!=NULL && pData->file!=NULL) {
198        T_FileStream_write(pData->file, &byte, 1);
199    }
200}
201
202U_CAPI void U_EXPORT2
203udata_write16(UNewDataMemory *pData, uint16_t word) {
204    if(pData!=NULL && pData->file!=NULL) {
205        T_FileStream_write(pData->file, &word, 2);
206    }
207}
208
209U_CAPI void U_EXPORT2
210udata_write32(UNewDataMemory *pData, uint32_t wyde) {
211    if(pData!=NULL && pData->file!=NULL) {
212        T_FileStream_write(pData->file, &wyde, 4);
213    }
214}
215
216U_CAPI void U_EXPORT2
217udata_writeBlock(UNewDataMemory *pData, const void *s, int32_t length) {
218    if(pData!=NULL && pData->file!=NULL) {
219        if(length>0) {
220            T_FileStream_write(pData->file, s, length);
221        }
222    }
223}
224
225U_CAPI void U_EXPORT2
226udata_writePadding(UNewDataMemory *pData, int32_t length) {
227    static const uint8_t padding[16]={
228        0xaa, 0xaa, 0xaa, 0xaa,
229        0xaa, 0xaa, 0xaa, 0xaa,
230        0xaa, 0xaa, 0xaa, 0xaa,
231        0xaa, 0xaa, 0xaa, 0xaa
232    };
233    if(pData!=NULL && pData->file!=NULL) {
234        while(length>=16) {
235            T_FileStream_write(pData->file, padding, 16);
236            length-=16;
237        }
238        if(length>0) {
239            T_FileStream_write(pData->file, padding, length);
240        }
241    }
242}
243
244U_CAPI void U_EXPORT2
245udata_writeString(UNewDataMemory *pData, const char *s, int32_t length) {
246    if(pData!=NULL && pData->file!=NULL) {
247        if(length==-1) {
248            length=(int32_t)uprv_strlen(s);
249        }
250        if(length>0) {
251            T_FileStream_write(pData->file, s, length);
252        }
253    }
254}
255
256U_CAPI void U_EXPORT2
257udata_writeUString(UNewDataMemory *pData, const UChar *s, int32_t length) {
258    if(pData!=NULL && pData->file!=NULL) {
259        if(length==-1) {
260            length=u_strlen(s);
261        }
262        if(length>0) {
263            T_FileStream_write(pData->file, s, length*sizeof(UChar));
264        }
265    }
266}
267
268/*
269 * Hey, Emacs, please set the following:
270 *
271 * Local Variables:
272 * indent-tabs-mode: nil
273 * End:
274 *
275 */
276
277