|
HMDT - Special Issue / CoreFoundation の秘密 / String Services - 固定文字列の作り方 |
- String Servcies -
|
|
CoreFoundation/String.subporj/CFString.c
|
__private_extern__ CFStringRef __CFStringCreateImmutableFunnel3(
CFAllocatorRef alloc,
const void *bytes,
CFIndex numBytes,
CFStringEncoding encoding,
Boolean possiblyExternalFormat,
Boolean tryToReduceUnicode,
Boolean hasLengthByte,
Boolean hasNullByte,
Boolean noCopy,
CFAllocatorRef contentsDeallocator,
UInt32 converterFlags)
|
固定長文字列の CFString を作る関数だ。たくさんの引数があるけど、それぞれの意味はこんな感じ。
alloc
メモリのアロケータbytes
文字列データnumBytes
文字列データの長さ(バイトで)encoding
エンコーディングpossiblyExternalFormat
BOM (Byte Order Mark) が含まれていて、それがスワップされている可能性があるかtryToReduceUnicode
16 bit Unichar じゃなくて、ASCII 8 bit でできるかどうかチェックするか。CFStringCreateWithCharacters だけは truehasLengthByte
長さがデータに埋め込まれているか。Pascal 文字列のときは truehasNullByte
NULL で終わっているか。C 文字列のときは truenoCopy
データをコピーしないか。NoCopy 関数のときは truecontentsDeallocator
デアロケータconverterFlags
エンコーディングするときに使われるフラグ
と、いうわけで、これらが文字列作成に必要なデータだ。基本は、文字列データと、その長さと、エンコーディングだね。
![]()
前の項で見たように、CFString はすぐ下に文字列データがあるインライン型と、外部にデータを保持する型とがある。どちらを使うかは、CFVeryPrivate.h にある __kCFVarWidthLocalBufferSize の値で決まる。
|
CoreFoundation/Base.subproj/CFVeryPrivate.h
|
enum {
__kCFVarWidthLocalBufferSize = 1008
};
|
この値より小さかったらインラインで、大きかったら外部に文字列データを置くことになる。現在の値は 1008。半端な大きさなのは、このデータの前に __CFString 構造体のメンバである CFRuntimeBase と length が来るからだな、きっと。
![]()
では、問題の関数 __CFStringCreateImmutableFunnel3() の実装を調べてみよう。ここでの主な仕事は、
エンコードが指定されてたらデコードする
これは __CFStringDecodeByteStream3() で行われるんだASCII にできそうだったら ASCII にする
これで 8 bit のデータになる文字列のサイズを確定する
文字列を Unicode か ASCII 表現にして、最終的に必要なサイズを決定するんだ文字列データを設定
インラインだったらコピーして、そうじゃなかったらポインタを設定する
といった感じか。けっこう大きい関数なので、フローチャートにしてみた。

処理の流れはこんなところか。それぞれの細かい処理はソースコードを見てくれ。、、、っていうだけだとしまりが悪いので、最後のところだけ抜き出してみよう。CFString のインスタンスを作って、文字列データを設定するところだ。
|
CoreFoundation/String.subproj/CFString.c
|
__private_extern__ CFStringRef __CFStringCreateImmutableFunnel3(
CFAllocatorRef alloc,
const void *bytes,
CFIndex numBytes,
CFStringEncoding encoding,
Boolean possiblyExternalFormat,
Boolean tryToReduceUnicode,
Boolean hasLengthByte,
Boolean hasNullByte,
Boolean noCopy,
CFAllocatorRef contentsDeallocator,
UInt32 converterFlags)
{
CFMutableStringRef str;
CFVarWidthCharBuffer vBuf;
CFIndex size;
Boolean useLengthByte = false;
Boolean useNullByte = false;
Boolean useInlineData = false;
...
/* CFString のインスタンスを確保 */
// Finally, allocate!
str = (CFMutableStringRef)_CFRuntimeCreateInstance(
alloc, __kCFStringTypeID, size, NULL);
...
if (useInlineData) {
/* インラインデータの場合 */
uint8_t *contents = (uint8_t *)__CFStrContents(str);
if (useLengthByte && !hasLengthByte) *contents++ = numBytes;
/* メモリコピー */
memmove(contents, bytes, numBytes);
if (useNullByte) contents[numBytes] = 0;
} else {
/* インラインじゃない場合 */
/* 文字列のポインタ設定 */
__CFStrSetContentPtr(str, bytes);
if (contentsDeallocator != alloc &&
contentsDeallocator != kCFAllocatorNull)
__CFStrSetContentsDeallocator(str, CFRetain(contentsDeallocator));
}
if (vBuf.shouldFreeChars) CFAllocatorDeallocate(vBuf.allocator, (void *)bytes);
return str;
}
|
というわけで、最終的にはメモリを確保してそこにコピーするわけだね。ま、あたりまえだが。さて、これで文字列データの確保の仕方は分かった。だけどもう 1 つ CFString の作成で興味深いのは、エンコーディングの部分だよな。エンコーディングは __CFStringDecodeByteStream3() っていう関数の中で処理されている。これについては、別の項で見ていくぜ。
(Nov. 22, 2002)
|
Home | Link | Download | Back Number | Speciall Issue
|