basename=findBasename(filename);
len = static_cast<int32_t>(strlen(basename)) - 4; /* -4: subtract the length of ".dat" */
if(len<=0 || 0!=strcmp(basename+len, ".dat")) {
fprintf(stderr, "icupkg: \"%s\" is not recognized as a package filename (must end with .dat)\n",
basename); exit(U_ILLEGAL_ARGUMENT_ERROR);
}
if(len>=capacity) {
fprintf(stderr, "icupkg: the package name \"%s\" is too long (>=%ld)\n",
basename, static_cast<long>(capacity)); exit(U_ILLEGAL_ARGUMENT_ERROR);
}
/* * Prepend the path (if any) to the name and run the name through treeToName().
*/ staticvoid
makeFullFilename(constchar *path, constchar *name, char *filename, int32_t capacity) { char *s;
// prepend the path unless nullptr or empty if(path!=nullptr && path[0]!=0) { if (static_cast<int32_t>(strlen(path) + 1) >= capacity) {
fprintf(stderr, "pathname too long: \"%s\"\n", path); exit(U_BUFFER_OVERFLOW_ERROR);
}
strcpy(filename, path);
// make sure the path ends with a file separator
s=strchr(filename, 0); if(*(s-1)!=U_FILE_SEP_CHAR && *(s-1)!=U_FILE_ALT_SEP_CHAR) {
*s++=U_FILE_SEP_CHAR;
}
} else {
s=filename;
}
// turn the name into a filename, turn tree separators into file separators if (static_cast<int32_t>((s - filename) + strlen(name)) >= capacity) {
fprintf(stderr, "path/filename too long: \"%s%s\"\n", filename, name); exit(U_BUFFER_OVERFLOW_ERROR);
}
strcpy(s, name);
treeToPath(s);
}
/* open the input file, get its length, allocate memory for it, read the file */
file=fopen(filename, "rb"); if(file==nullptr) {
fprintf(stderr, "icupkg: unable to open input file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR);
}
/* pad the file to a multiple of 16 using the usual padding byte */ if(fileLength<length) {
memset(data.getAlias()+fileLength, 0xaa, length-fileLength);
}
fclose(file);
// minimum check for ICU-format data
errorCode=U_ZERO_ERROR;
typeEnum=getTypeEnumForInputData(data.getAlias(), length, &errorCode); if(typeEnum<0 || U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: not an ICU data file: \"%s\"\n", filename); #if !UCONFIG_NO_LEGACY_CONVERSION exit(U_INVALID_FORMAT_ERROR); #else
fprintf(stderr, "U_INVALID_FORMAT_ERROR occurred but UCONFIG_NO_LEGACY_CONVERSION is on so this is expected.\n"); exit(0); #endif
}
type=makeTypeLetter(typeEnum);
/* read the file */
inData=readFile(nullptr, filename, inLength, type);
length=inLength;
/* * swap the header - even if the swapping itself is a no-op * because it tells us the header length
*/
errorCode=U_ZERO_ERROR;
makeTypeProps(type, inCharset, inIsBigEndian);
ds=udata_openSwapper(inIsBigEndian, inCharset, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode); if(U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: udata_openSwapper(\"%s\") failed - %s\n",
filename, u_errorName(errorCode)); exit(errorCode);
}
/* check data format and format version */
pInfo = reinterpret_cast<const UDataInfo*>(reinterpret_cast<constchar*>(inData) + 4); if(!(
pInfo->dataFormat[0]==0x43 && /* dataFormat="CmnD" */
pInfo->dataFormat[1]==0x6d &&
pInfo->dataFormat[2]==0x6e &&
pInfo->dataFormat[3]==0x44 &&
pInfo->formatVersion[0]==1
)) {
fprintf(stderr, "icupkg: data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as an ICU .dat package\n",
pInfo->dataFormat[0], pInfo->dataFormat[1],
pInfo->dataFormat[2], pInfo->dataFormat[3],
pInfo->formatVersion[0]); exit(U_UNSUPPORTED_ERROR);
}
inIsBigEndian = static_cast<UBool>(pInfo->isBigEndian);
inCharset=pInfo->charsetFamily;
/* check that the itemCount fits, then the ToC table, then at least the header of the last item */
length-=headerLength; if(length<4) { /* itemCount does not fit */
offset=0x7fffffff;
} else {
itemCount = udata_readInt32(ds, *reinterpret_cast<const int32_t*>(inBytes));
setItemCapacity(itemCount); /* resize so there's space */ if(itemCount==0) {
offset=4;
} elseif(length<(4+8*itemCount)) { /* ToC table does not fit */
offset=0x7fffffff;
} else { /* offset of the last item plus at least 20 bytes for its header */
offset = 20 + static_cast<int32_t>(ds->readUInt32(inEntries[itemCount - 1].dataOffset));
}
} if(length<offset) {
fprintf(stderr, "icupkg: too few bytes (%ld after header) for a .dat package\n", static_cast<long>(length)); exit(U_INDEX_OUTOFBOUNDS_ERROR);
} /* do not modify the package length variable until the last item's length is set */
if(itemCount<=0) { if(doAutoPrefix) {
fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but the input package is empty\n"); exit(U_INVALID_FORMAT_ERROR);
}
} else { char prefix[MAX_PKG_NAME_LENGTH+4]; char *s, *inItemStrings;
if(itemCount>itemMax) {
fprintf(stderr, "icupkg: too many items, maximum is %d\n", itemMax); exit(U_BUFFER_OVERFLOW_ERROR);
}
/* swap the item name strings */
int32_t stringsOffset=4+8*itemCount;
itemLength = static_cast<int32_t>(ds->readUInt32(inEntries[0].dataOffset)) - stringsOffset;
// don't include padding bytes at the end of the item names while(itemLength>0 && inBytes[stringsOffset+itemLength-1]!=0) {
--itemLength;
}
if((inStringTop+itemLength)>STRING_STORE_SIZE) {
fprintf(stderr, "icupkg: total length of item name strings too long\n"); exit(U_BUFFER_OVERFLOW_ERROR);
}
inItemStrings=inStrings+inStringTop;
ds->swapInvChars(ds, inBytes+stringsOffset, itemLength, inItemStrings, &errorCode); if(U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg failed to swap the input .dat package item name strings\n"); exit(U_INVALID_FORMAT_ERROR);
}
inStringTop+=itemLength;
// reset the Item entries
memset(items, 0, itemCount*sizeof(Item));
/* * Get the common prefix of the items. * New-style ICU .dat packages use tree separators ('/') between package names, * tree names, and item names, * while old-style ICU .dat packages (before multi-tree support) * use an underscore ('_') between package and item names.
*/
offset = static_cast<int32_t>(ds->readUInt32(inEntries[0].nameOffset)) - stringsOffset;
s=inItemStrings+offset; // name of the first entry
int32_t prefixLength; if(doAutoPrefix) { // Use the first entry's prefix. Must be a new-style package. constchar *prefixLimit=strchr(s, U_TREE_ENTRY_SEP_CHAR); if(prefixLimit==nullptr) {
fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but " "the first entry \"%s\" does not contain a '%c'\n",
s, U_TREE_ENTRY_SEP_CHAR); exit(U_INVALID_FORMAT_ERROR);
}
prefixLength = static_cast<int32_t>(prefixLimit - s); if(prefixLength==0 || prefixLength>=UPRV_LENGTHOF(pkgPrefix)) {
fprintf(stderr, "icupkg: --auto_toc_prefix[_with_type] but " "the prefix of the first entry \"%s\" is empty or too long\n",
s); exit(U_INVALID_FORMAT_ERROR);
} if(prefixEndsWithType && s[prefixLength-1]!=type) {
fprintf(stderr, "icupkg: --auto_toc_prefix_with_type but " "the prefix of the first entry \"%s\" does not end with '%c'\n",
s, type); exit(U_INVALID_FORMAT_ERROR);
}
memcpy(pkgPrefix, s, prefixLength);
pkgPrefix[prefixLength]=0;
memcpy(prefix, s, ++prefixLength); // include the /
} else { // Use the package basename as prefix.
int32_t inPkgNameLength= static_cast<int32_t>(strlen(inPkgName));
memcpy(prefix, inPkgName, inPkgNameLength);
prefixLength=inPkgNameLength;
if (static_cast<int32_t>(strlen(s)) >= (inPkgNameLength + 2) &&
0==memcmp(s, inPkgName, inPkgNameLength) &&
s[inPkgNameLength]=='_'
) { // old-style .dat package
prefix[prefixLength++]='_';
} else { // new-style .dat package
prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR; // if it turns out to not contain U_TREE_ENTRY_SEP_CHAR // then the test in the loop below will fail
}
}
prefix[prefixLength]=0;
/* read the ToC table */ for(i=0; i<itemCount; ++i) { // skip the package part of the item name, error if it does not match the actual package name // or if nothing follows the package name
offset = static_cast<int32_t>(ds->readUInt32(inEntries[i].nameOffset)) - stringsOffset;
s=inItemStrings+offset; if(0!=strncmp(s, prefix, prefixLength) || s[prefixLength]==0) {
fprintf(stderr, "icupkg: input .dat item name \"%s\" does not start with \"%s\"\n",
s, prefix); exit(U_INVALID_FORMAT_ERROR);
}
items[i].name=s+prefixLength;
// set the item's data
items[i].data = const_cast<uint8_t*>(inBytes) + ds->readUInt32(inEntries[i].dataOffset); if(i>0) {
items[i - 1].length = static_cast<int32_t>(items[i].data - items[i - 1].data);
// set the previous item's platform type
typeEnum=getTypeEnumForInputData(items[i-1].data, items[i-1].length, &errorCode); if(typeEnum<0 || U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: not an ICU data file: item \"%s\" in \"%s\"\n", items[i-1].name, filename); exit(U_INVALID_FORMAT_ERROR);
}
items[i-1].type=makeTypeLetter(typeEnum);
}
items[i].isDataOwned=false;
} // set the last item's length
items[itemCount-1].length=length-ds->readUInt32(inEntries[itemCount-1].dataOffset);
// set the last item's platform type
typeEnum=getTypeEnumForInputData(items[itemCount-1].data, items[itemCount-1].length, &errorCode); if(typeEnum<0 || U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: not an ICU data file: item \"%s\" in \"%s\"\n", items[itemCount-1].name, filename); exit(U_INVALID_FORMAT_ERROR);
}
items[itemCount-1].type=makeTypeLetter(typeEnum);
if(type!=U_ICUDATA_TYPE_LETTER[0]) { // sort the item names for the local charset
sortItems();
}
}
// if there is an explicit comment, then use it, else use what's in the current header if(comment!=nullptr) { /* get the header size minus the current comment */
DataHeader *pHeader;
int32_t length;
pHeader = reinterpret_cast<DataHeader*>(header);
headerLength=4+pHeader->info.size;
length = static_cast<int32_t>(strlen(comment)); if ((headerLength + length) >= static_cast<int32_t>(sizeof(header))) {
fprintf(stderr, "icupkg: comment too long\n"); exit(U_BUFFER_OVERFLOW_ERROR);
}
memcpy(header+headerLength, comment, length+1);
headerLength+=length; if(headerLength&0xf) { /* NUL-pad the header to a multiple of 16 */
length=(headerLength+0xf)&~0xf;
memset(header+headerLength, 0, length-headerLength);
headerLength=length;
}
pHeader->dataHeader.headerSize = static_cast<uint16_t>(headerLength);
}
// create the file and write its contents
file=fopen(filename, "wb"); if(file==nullptr) {
fprintf(stderr, "icupkg: unable to create file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR);
}
// swap and write the header if(dsLocalToOut!=nullptr) {
udata_swapDataHeader(dsLocalToOut, header, headerLength, header, &errorCode); if(U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: udata_swapDataHeader(local to out) failed - %s\n", u_errorName(errorCode)); exit(errorCode);
}
}
length = static_cast<int32_t>(fwrite(header, 1, headerLength, file)); if(length!=headerLength) {
fprintf(stderr, "icupkg: unable to write complete header to file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR);
}
// prepare and swap the package name with a tree separator // for prepending to item names if(pkgPrefix[0]==0) {
prefixLength = static_cast<int32_t>(strlen(prefix));
} else {
prefixLength = static_cast<int32_t>(strlen(pkgPrefix));
memcpy(prefix, pkgPrefix, prefixLength); if(prefixEndsWithType) {
prefix[prefixLength-1]=outType;
}
}
prefix[prefixLength++]=U_TREE_ENTRY_SEP_CHAR;
prefix[prefixLength]=0; if(dsLocalToOut!=nullptr) {
dsLocalToOut->swapInvChars(dsLocalToOut, prefix, prefixLength, prefix, &errorCode); if(U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: swapInvChars(output package name) failed - %s\n", u_errorName(errorCode)); exit(errorCode);
}
// swap and sort the item names (sorting needs to be done in the output charset)
dsLocalToOut->swapInvChars(dsLocalToOut, inStrings, inStringTop, inStrings, &errorCode); if(U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: swapInvChars(item names) failed - %s\n", u_errorName(errorCode)); exit(errorCode);
}
sortItems();
}
// create the output item names in sorted order, with the package name prepended to each for(i=0; i<itemCount; ++i) {
length = static_cast<int32_t>(strlen(items[i].name));
name=allocString(false, length+prefixLength);
memcpy(name, prefix, prefixLength);
memcpy(name+prefixLength, items[i].name, length+1);
items[i].name=name;
}
// calculate offsets for item names and items, pad to 16-align items // align only the first item; each item's length is a multiple of 16
basenameOffset=4+8*itemCount;
offset=basenameOffset+outStringTop; if((length=(offset&15))!=0) {
length=16-length;
memset(allocString(false, length-1), 0xaa, length);
offset+=length;
}
// write the table of contents // first the itemCount
outInt32=itemCount; if(dsLocalToOut!=nullptr) {
dsLocalToOut->swapArray32(dsLocalToOut, &outInt32, 4, &outInt32, &errorCode); if(U_FAILURE(errorCode)) {
fprintf(stderr, "icupkg: swapArray32(item count) failed - %s\n", u_errorName(errorCode)); exit(errorCode);
}
}
length = static_cast<int32_t>(fwrite(&outInt32, 1, 4, file)); if(length!=4) {
fprintf(stderr, "icupkg: unable to write complete item count to file \"%s\"\n", filename); exit(U_FILE_ACCESS_ERROR);
}
int32_t
Package::findItem(constchar *name, int32_t length) const {
int32_t i, start, limit; int result;
/* do a binary search for the string */
start=0;
limit=itemCount; while(start<limit) {
i=(start+limit)/2; if(length>=0) {
result=strncmp(name, items[i].name, length);
} else {
result=strcmp(name, items[i].name);
}
if(result==0) { /* found */ if(length>=0) { /* * if we compared just prefixes, then we may need to back up * to the first item with this prefix
*/ while(i>0 && 0==strncmp(name, items[i-1].name, length)) {
--i;
}
} return i;
} elseif(result<0) {
limit=i;
} else/* result>0 */ {
start=i+1;
}
}
return ~start; /* not found, return binary-not of the insertion point */
}
while(findNextIndex<itemCount) {
idx=findNextIndex++;
name=items[idx].name;
nameLength = static_cast<int32_t>(strlen(name)); if(nameLength<(findPrefixLength+findSuffixLength)) { // item name too short for prefix & suffix continue;
} if(findPrefixLength>0 && 0!=memcmp(findPrefix, name, findPrefixLength)) { // left the range of names with this prefix break;
}
middle=name+findPrefixLength;
middleLength=nameLength-findPrefixLength-findSuffixLength; if(findSuffixLength>0 && 0!=memcmp(findSuffix, name+(nameLength-findSuffixLength), findSuffixLength)) { // suffix does not match continue;
} // prefix & suffix match
if(matchMode&MATCH_NOSLASH) {
treeSep=strchr(middle, U_TREE_ENTRY_SEP_CHAR); if(treeSep!=nullptr && (treeSep-middle)<middleLength) { // the middle (matching the * wildcard) contains a tree separator / continue;
}
}
idx=findItem(name); if(idx<0) { // new item, make space at the insertion point
ensureItemCapacity(); // move the following items down
idx=~idx; if(idx<itemCount) {
memmove(items+idx+1, items+idx, (itemCount-idx)*sizeof(Item));
}
++itemCount;
// reset this Item entry
memset(items+idx, 0, sizeof(Item));
// copy the item's name
items[idx].name=allocString(true, static_cast<int32_t>(strlen(name)));
strcpy(items[idx].name, name);
pathToTree(items[idx].name);
} else { // same-name item found, replace it if(items[idx].isDataOwned) {
uprv_free(items[idx].data);
}
// keep the item's name since it is the same
}
// set the item's data
items[idx].data=data;
items[idx].length=length;
items[idx].isDataOwned=isDataOwned;
items[idx].type=type;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.