1// Common/ListFileUtils.cpp
2
3#include "StdAfx.h"
4
5#include "../../C/CpuArch.h"
6
7#include "ListFileUtils.h"
8#include "MyBuffer.h"
9#include "StringConvert.h"
10#include "UTFConvert.h"
11
12#include "../Windows/FileIO.h"
13
14#define CSysInFile NWindows::NFile::NIO::CInFile
15#define MY_GET_LAST_ERROR ::GetLastError()
16
17
18#define kQuoteChar '\"'
19
20
21static void AddName(UStringVector &strings, UString &s)
22{
23  s.Trim();
24  if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar)
25  {
26    s.DeleteBack();
27    s.Delete(0);
28  }
29  if (!s.IsEmpty())
30    strings.Add(s);
31}
32
33
34static bool My_File_Read(CSysInFile &file, void *data, size_t size, DWORD &lastError)
35{
36  size_t processed;
37  if (!file.ReadFull(data, size, processed))
38  {
39    lastError = MY_GET_LAST_ERROR;
40    return false;
41  }
42  if (processed != size)
43  {
44    lastError = 1; // error: size of listfile was changed
45    return false;
46  }
47  return true;
48}
49
50
51bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, DWORD &lastError)
52{
53  lastError = 0;
54  CSysInFile file;
55  if (!file.Open(fileName))
56  {
57    lastError = MY_GET_LAST_ERROR;
58    return false;
59  }
60  UInt64 fileSize;
61  if (!file.GetLength(fileSize))
62  {
63    lastError = MY_GET_LAST_ERROR;
64    return false;
65  }
66  if (fileSize >= ((UInt32)1 << 31) - 32)
67    return false;
68  UString u;
69  if (codePage == Z7_WIN_CP_UTF16 || codePage == Z7_WIN_CP_UTF16BE)
70  {
71    if ((fileSize & 1) != 0)
72      return false;
73    CByteArr buf((size_t)fileSize);
74
75    if (!My_File_Read(file, buf, (size_t)fileSize, lastError))
76      return false;
77
78    file.Close();
79    const unsigned num = (unsigned)fileSize / 2;
80    wchar_t *p = u.GetBuf(num);
81    if (codePage == Z7_WIN_CP_UTF16)
82      for (unsigned i = 0; i < num; i++)
83      {
84        wchar_t c = GetUi16(buf + (size_t)i * 2);
85        if (c == 0)
86          return false;
87        p[i] = c;
88      }
89    else
90      for (unsigned i = 0; i < num; i++)
91      {
92        wchar_t c = (wchar_t)GetBe16(buf + (size_t)i * 2);
93        if (c == 0)
94          return false;
95        p[i] = c;
96      }
97    p[num] = 0;
98    u.ReleaseBuf_SetLen(num);
99  }
100  else
101  {
102    AString s;
103    char *p = s.GetBuf((unsigned)fileSize);
104
105    if (!My_File_Read(file, p, (size_t)fileSize, lastError))
106      return false;
107
108    file.Close();
109    s.ReleaseBuf_CalcLen((unsigned)fileSize);
110    if (s.Len() != fileSize)
111      return false;
112
113    // #ifdef CP_UTF8
114    if (codePage == CP_UTF8)
115    {
116      // we must check UTF8 here, if convert function doesn't check
117      if (!CheckUTF8_AString(s))
118        return false;
119      if (!ConvertUTF8ToUnicode(s, u))
120        return false;
121    }
122    else
123    // #endif
124      MultiByteToUnicodeString2(u, s, codePage);
125  }
126
127  const wchar_t kGoodBOM = 0xFEFF;
128  // const wchar_t kBadBOM  = 0xFFFE;
129
130  UString s;
131  unsigned i = 0;
132  for (; i < u.Len() && u[i] == kGoodBOM; i++);
133  for (; i < u.Len(); i++)
134  {
135    wchar_t c = u[i];
136    /*
137    if (c == kGoodBOM || c == kBadBOM)
138      return false;
139    */
140    if (c == '\n' || c == 0xD)
141    {
142      AddName(strings, s);
143      s.Empty();
144    }
145    else
146      s += c;
147  }
148  AddName(strings, s);
149  return true;
150}
151