1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
* Copyright (c) 2004,2011 International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
* Created: March 19 2004
* Since: ICU 3.0
**********************************************************************
*/
#include "textfile.h"
#include "cmemory.h"
#include "cstring.h"
#include "intltest.h"
#include "util.h"
// If the symbol CCP is defined, then the 'name' and 'encoding'
// constructor parameters are copied. Otherwise they are aliased.
// #define CCP
TextFile::TextFile(const char* _name, const char* _encoding, UErrorCode& ec) :
file(nullptr),
name(nullptr), encoding(nullptr),
buffer(nullptr),
capacity(0),
lineNo(0)
{
if (U_FAILURE(ec) || _name == nullptr || _encoding == nullptr) {
if (U_SUCCESS(ec)) {
ec = U_ILLEGAL_ARGUMENT_ERROR;
}
return;
}
#ifdef CCP
name = uprv_malloc(uprv_strlen(_name) + 1);
encoding = uprv_malloc(uprv_strlen(_encoding) + 1);
if (name == 0 || encoding == 0) {
ec = U_MEMORY_ALLOCATION_ERROR;
return;
}
uprv_strcpy(name, _name);
uprv_strcpy(encoding, _encoding);
#else
name = const_cast<char*>(_name);
encoding = const_cast<char*>(_encoding);
#endif
const char* testDir = IntlTest::getSourceTestData(ec);
if (U_FAILURE(ec)) {
return;
}
if (!ensureCapacity(static_cast<int32_t>(uprv_strlen(testDir) + uprv_strlen(name) + 1))) {
ec = U_MEMORY_ALLOCATION_ERROR;
return;
}
uprv_strcpy(buffer, testDir);
uprv_strcat(buffer, name);
file = T_FileStream_open(buffer, "rb");
if (file == nullptr) {
ec = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
}
TextFile::~TextFile() {
if (file != nullptr) T_FileStream_close(file);
if (buffer != nullptr) uprv_free(buffer);
#ifdef CCP
uprv_free(name);
uprv_free(encoding);
#endif
}
UBool TextFile::readLine(UnicodeString& line, UErrorCode& ec) {
if (T_FileStream_eof(file)) {
return false;
}
// Note: 'buffer' may change after ensureCapacity() is called,
// so don't use
// p=buffer; *p++=c;
// but rather
// i=; buffer[i++]=c;
int32_t n = 0;
for (;;) {
int c = T_FileStream_getc(file); // sic: int, not int32_t
if (c < 0 || c == 0xD || c == 0xA) {
// consume 0xA following 0xD
if (c == 0xD) {
c = T_FileStream_getc(file);
if (c != 0xA && c >= 0) {
T_FileStream_ungetc(c, file);
}
}
break;
}
if (!setBuffer(n++, c, ec)) return false;
}
if (!setBuffer(n++, 0, ec)) return false;
UnicodeString str(buffer, encoding);
// Remove BOM in first line, if present
if (lineNo == 0 && str[0] == 0xFEFF) {
str.remove(0, 1);
}
++lineNo;
line = str.unescape();
return true;
}
UBool TextFile::readLineSkippingComments(UnicodeString& line, UErrorCode& ec,
UBool trim) {
for (;;) {
if (!readLine(line, ec)) return false;
// Skip over white space
int32_t pos = 0;
ICU_Utility::skipWhitespace(line, pos, true);
// Ignore blank lines and comment lines
if (pos == line.length() || line.charAt(pos) == 0x23/*'#'*/) {
continue;
}
// Process line
if (trim) line.remove(0, pos);
return true;
}
}
/**
* Set buffer[index] to c, growing buffer if necessary. Return true if
* successful.
*/
UBool TextFile::setBuffer(int32_t index, char c, UErrorCode& ec) {
if (capacity <= index) {
if (!ensureCapacity(index+1)) {
ec = U_MEMORY_ALLOCATION_ERROR;
return false;
}
}
buffer[index] = c;
return true;
}
/**
* Make sure that 'buffer' has at least 'mincapacity' bytes.
* Return true upon success. Upon return, 'buffer' may change
* value. In any case, previous contents are preserved.
*/
#define LOWEST_MIN_CAPACITY 64
UBool TextFile::ensureCapacity(int32_t mincapacity) {
if (capacity >= mincapacity) {
return true;
}
// Grow by factor of 2 to prevent frequent allocation
// Note: 'capacity' may be 0
int32_t i = (capacity < LOWEST_MIN_CAPACITY)? LOWEST_MIN_CAPACITY: capacity;
while (i < mincapacity) {
i <<= 1;
if (i < 0) {
i = 0x7FFFFFFF;
break;
}
}
mincapacity = i;
// Simple realloc() no good; contents not preserved
// Note: 'buffer' may be 0
char* newbuffer = static_cast<char*>(uprv_malloc(mincapacity));
if (newbuffer == nullptr) {
return false;
}
if (buffer != nullptr) {
uprv_strncpy(newbuffer, buffer, capacity);
uprv_free(buffer);
}
buffer = newbuffer;
capacity = mincapacity;
return true;
}
|