1 
2 
3 #include "studiox_includes.h"
4 #include "xml_writer.h"
5 #include "xml_reader.h"
6 #include "csv_read_write.h"
7 #include "config_languages_dlg.h"
8 
9 ///////////////////////////////////////////////////////////////////////////////
csv_read_write()10 csv_read_write::csv_read_write()
11 {
12     mpLine = NULL;
13     mpBuffer = NULL;
14 }
15 
16 ///////////////////////////////////////////////////////////////////////////////
ExportLanguage(studiox_project * project)17 BOOL csv_read_write::ExportLanguage(studiox_project *project)
18 {
19     int index;
20     int src_language = project->mHeader.string_export_src;
21     int target_language = project->mHeader.string_export_target;
22     CString tag_data;
23     CString src_data;
24     CString pathname = project->mHeader.string_export_path;
25     pathname += "\\";
26     pathname += project->mHeader.string_export_filename;
27 
28     GotoProjectDirectory();
29     CStdioFile file;
30 
31     if (!file.Open(pathname, CFile::modeCreate | CFile::modeWrite))
32     {
33         return FALSE;
34     }
35 
36     int display = GetProjectView()->GetActiveDisplay();
37     string_table *table = project->mDisplays[display].stable;
38 
39     tag_data.Format(_T("name,%s,%s\n"),
40         config_languages_dlg::GetLanguageId(src_language),
41         config_languages_dlg::GetLanguageId(target_language));
42 
43     //write BOM mark
44     unsigned char BOM_mark[] = { 0xef, 0xbb, 0xbf };
45     file.Write(BOM_mark, 3);
46 
47     //write header line
48     WriteString(&file, tag_data);
49 
50     src_language = config_languages_dlg::GetStringTableIndexFromLanguageIndex(project, src_language);
51     target_language = config_languages_dlg::GetStringTableIndexFromLanguageIndex(project, target_language);
52 
53     if (src_language == -1)
54     {
55         return FALSE;
56     }
57 
58     CString csv_line;
59 
60     for (index = 0; index < table->CountStrings(); index++)
61     {
62         src_data = table->GetString(index, src_language);
63         if (!src_data.IsEmpty())
64         {
65             //string id
66             csv_line = table->GetStringId(index);
67             csv_line.Append(_T(","));
68 
69             //source language string
70             src_data = MakeCsvFormatValue(src_data);
71             csv_line.Append(src_data);
72 
73             //target language string
74             if (target_language >= 0)
75             {
76                 csv_line.Append(_T(","));
77                 tag_data = table->GetString(index, target_language);
78                 tag_data = MakeCsvFormatValue(tag_data);
79                 csv_line.Append(tag_data);
80             }
81             csv_line.Append(_T("\n"));
82 
83             WriteString(&file, csv_line);
84         }
85     }
86 
87     return TRUE;
88 }
89 
90 ///////////////////////////////////////////////////////////////////////////////
ImportCsvFile(studiox_project * project,CString & pathname)91 BOOL csv_read_write::ImportCsvFile(studiox_project *project, CString &pathname)
92 {
93     CString src_language;
94     CString target_language;
95     CString string_id;
96     CString src_string;
97     CString target_string;
98     CString notes("");
99     BOOL status = TRUE;
100 
101     int language_index;
102     int target_table_column;
103     int src_table_column;
104 
105     int display = GetProjectView()->GetActiveDisplay();
106     string_table *table = project->mDisplays[display].stable;
107 
108     ReadFile(pathname);
109 
110     CString line;
111     CStringArray header_array;
112     GotoProjectDirectory();
113 
114     ReadLine(line);
115     SplitString(line, ',', &header_array);
116 
117     // Get the version information
118 
119     if (header_array.GetCount() >= 3)
120     {
121         //there should be at lease 3 columns
122         int col, index;
123         CStringArray string_array;
124 
125         src_language = header_array.GetAt(1);
126         language_index = config_languages_dlg::GetLanguageIdIndex(src_language);
127         src_table_column = config_languages_dlg::GetStringTableIndexFromLanguageIndex(project, language_index);
128 
129         if (src_table_column == -1)
130         {
131             delete[]mpBuffer;
132             mpBuffer = NULL;
133             mpLine = NULL;
134             return FALSE;
135         }
136 
137         while (ReadLine(line))
138         {
139             index = 0;
140             string_array.RemoveAll();
141             SplitCsvLine(line, string_array);
142 
143             if (string_array.GetCount() < 2)
144             {
145                 //string id and source language should be valid
146                 status = FALSE;
147                 break;
148             }
149 
150             string_id = string_array.GetAt(0);
151             src_string = string_array.GetAt(1);
152 
153             for (col = 2; col < header_array.GetCount(); col++)
154             {
155                 target_language = header_array.GetAt(col);
156                 language_index = config_languages_dlg::GetLanguageIdIndex(target_language);
157                 target_table_column = config_languages_dlg::GetStringTableIndexFromLanguageIndex(project, language_index);
158 
159                 if (target_table_column == -1)
160                 {
161                     // the translation language doesn't exist in our project, so add it
162                     //target_table_column = AddNewLanguage(language_index);
163                     target_table_column = project->AddLanguage(language_index);
164                 }
165 
166                 if (col < string_array.GetCount())
167                 {
168                     target_string = string_array.GetAt(col);
169                 }
170                 else
171                 {
172                     target_string = _T("");
173                 }
174                 table->ImportString(string_id, src_string, target_string, notes, src_table_column, target_table_column);
175             }
176         }
177     }
178     else
179     {
180         status = FALSE;
181     }
182 
183     delete[]mpBuffer;
184     mpBuffer = NULL;
185     mpLine = NULL;
186 
187     table->Sort();
188     table->UpdateGuixLanguageTable();
189     return status;
190 }
191 
192 ///////////////////////////////////////////////////////////////////////////////
MakeCsvFormatValue(CString string)193 CString csv_read_write::MakeCsvFormatValue(CString string)
194 {
195     int index;
196     CString format_string;
197     BOOL embedded_special_character = FALSE;
198 
199     for (index = 0; index < string.GetLength(); index++)
200     {
201         switch (string.GetAt(index))
202         {
203         case '\"':
204         case '\r':
205         case '\n':
206         case ',':
207             embedded_special_character = TRUE;
208             break;
209         }
210     }
211 
212     //replace single double quotation with a pair of consecutive double quotes
213     string.Replace(_T("\""), _T("\"\""));
214 
215     if (embedded_special_character)
216     {
217         //put double quotation around string
218         string.Insert(0, '\"');
219         string.Append(_T("\""));
220     }
221 
222     return string;
223 }
224 
225 ///////////////////////////////////////////////////////////////////////////////
WriteString(CStdioFile * file,CString string)226 void csv_read_write::WriteString(CStdioFile *file, CString string)
227 {
228     // The maximun UTF8 character is 6 bytes, calculate the maximun utf8 buffer size needed for the string.
229     int char_count = _tcslen(string) * 6 + 1;
230     char *utf8buf = new char[char_count];
231     strcpy_s(utf8buf, char_count, CT2A(string, CP_UTF8));
232     file->Write(utf8buf, strlen(utf8buf));
233 
234     delete utf8buf;
235 }
236 
237 ///////////////////////////////////////////////////////////////////////////////
FindDelimiterIndex(CString line,int start_index)238 int csv_read_write::FindDelimiterIndex(CString line, int start_index)
239 {
240     int quatation_mark_count = 0;
241 
242     while (start_index < line.GetLength())
243     {
244         switch (line.GetAt(start_index))
245         {
246         case '\"':
247             quatation_mark_count++;
248             break;
249 
250         case ',':
251             if (!(quatation_mark_count & 0x1))
252             {
253                 //quotation mark should be paired
254                 return start_index;
255             }
256             break;
257         }
258 
259         start_index++;
260     }
261 
262     if (!(quatation_mark_count & 0x1))
263     {
264         //quotation mark should be paired
265         return start_index;
266     }
267 
268     return -1;
269 }
270 
271 ///////////////////////////////////////////////////////////////////////////////
SplitCsvLine(CString & line,CStringArray & line_array)272 void csv_read_write::SplitCsvLine(CString &line, CStringArray &line_array)
273 {
274     int index = 0;
275     int length = line.GetLength();
276     int start, end;
277     CString string;
278 
279     while (index < length)
280     {
281         start = index;
282         end = FindDelimiterIndex(line, start) - 1;
283 
284         if (end < 0)
285         {
286             //should not happen
287             return;
288         }
289 
290         index = end + 2;
291 
292         if (line.GetAt(start) == '\"')
293         {
294             //remove double quotation mark around the string
295             start += 1;
296             end -= 1;
297         }
298 
299         string = line.Mid(start, end - start + 1);
300 
301         //replace 2 double colon to 1 double colon
302         string.Replace(_T("\"\""), _T("\""));
303 
304         line_array.Add(string);
305     }
306 }
307 
308 ///////////////////////////////////////////////////////////////////////////////
ReadLine(CString & line)309 BOOL csv_read_write::ReadLine(CString &line)
310 {
311     int double_quotation_count = 0;
312 
313     if (!mpLine)
314     {
315         return FALSE;
316     }
317 
318     while (mpLine[0] && ((mpLine[0] == '\r') || (mpLine[0] == '\n')))
319     {
320         mpLine++;
321     }
322 
323     int line_end = 0;
324 
325     while (mpLine[line_end])
326     {
327         if ((mpLine[line_end] == '\r') || (mpLine[line_end] == '\n'))
328         {
329             if (!(double_quotation_count & 0x01))
330             {
331                 //double quotation mark should be paired
332                 break;
333             }
334         }
335         else if (mpLine[line_end] == '\"')
336         {
337             double_quotation_count++;
338         }
339 
340         line_end++;
341     }
342 
343     if (line_end)
344     {
345         char *buf = new char[line_end + 1];
346         strncpy(buf, mpLine, line_end);
347         buf[line_end] = '\0';
348 
349         line = CA2T(buf, CP_UTF8);
350         mpLine += line_end + 1;
351 
352         delete[] buf;
353         return TRUE;
354     }
355 
356     return FALSE;
357 }
358 
359 ///////////////////////////////////////////////////////////////////////////////
ReadFile(CString pathname)360 void csv_read_write::ReadFile(CString pathname)
361 {
362     CStdioFile file(pathname, CStdioFile::modeRead | CFile::shareExclusive);
363     ULONG size = (ULONG)file.GetLength();
364     mpBuffer = new char[size + 1];
365     memset(mpBuffer, 0, size + 1);
366     file.Read(mpBuffer, size);
367 
368     mpLine = mpBuffer;
369 
370     if (size >= 3)
371     {
372         if ((unsigned char)mpLine[0] == 0xef &&
373             (unsigned char)mpLine[1] == 0xbb &&
374             (unsigned char)mpLine[2] == 0xbf)
375         {
376             //skip BOM mark
377             mpLine += 3;
378         }
379     }
380 }