2016-11-29 8 views
1

Swiftに次のCコードを書くにはどうすればよいですか?TrueType 'cmap'形式を読む4 Swiftのサブテーブル3

単純なバイナリデータリーダーを使用して、フォーマット4のTrueType文字マッピングテーブルを読み取ろうとしています。 Cで作業しているときにポインタの頭や尾をつかむことができるので、ポインタの操作が関係するまではすべてうまくいきます。Unsafeという接頭辞を付けて偽装しているだけではありません。

私は複数のことを試みましたが、何も正しく動作しないようです。私はちょうどスウィフトのポインタ "アドレス"をどのように扱うか正確にはわからないと思う。

たとえば、ここに私はどこのより完全なアイデアです:上記のコードで

// The following variables are all [UInt16]: 
// - startCodes 
// - endCodes 
// - idDeltas 
// - idRangeOffsets 

var gids = [Int]() 

// Iterate segments, skipping the last character code (0xFFFF) 
for i in 0 ..< segCount - 1 { 

    let start = startCodes[i] 
    let end = endCodes[i] 
    let delta = idDeltas[i] 
    let rangeOffset = idRangeOffsets[i] 
    let charRange = start ..< (end + 1) 

    if rangeOffset == 0 { 
     gids.append(contentsOf: charRange.map { charCode in 
      return (charCode + delta) & 0xFFFF 
     }) 
    } 
    else { 
     for charCode in charRange { 
      // ??? 
     } 
    } 
} 

、あなたは???に気付くでしょう。これは、私が上記の奇妙なC-ポインタアドレスポインターハァットリックを使用してグリフインデックスを取得するところです。問題は、私はそれを理解できないということです。私は実際に理解して変数を置き換える、ここで私が持っているものです:

for charCode in charRange { 
     Not too sure about this Actual value of idRangeOffset[i] 
       |       | 
       v       v 
    glyphIndex = *(&idRangeOffset[i] + rangeOffset/2 + (charCode - start)) 
       ^
        | 
       Or this 
} 

は悟りへのパス上で私を導くことができるそこに任意のスウィフト3ポインターの達人はありますか?どんな助けでも大歓迎です!私はスウィフトに言葉によってあなたの擬似Cコードワードを翻訳した場合

+0

'glyphIndex'を作成するコードでは、外側の括弧の中の部分がポインタを作成します。これらの括弧の前にある '*'は、そのポインタによって*に指されたデータ*を取得します。 – Toby

+0

'&idRangeOffset [i]'は 'idRangeOffset [i]'の値のアドレスを取ります。 Cでは、これはポインタ、つまり別のオブジェクトのアドレスを保持する変数です。 2番目の部分である '+ rangeOffset/2 +(charCode - start)'は、*アドレス*にいくつかの値を追加して、他の場所を指すようにします。 – Toby

+0

これを迅速に正確に表現する方法私は恐れているとは思えません – Toby

答えて

1

が、それはこのようなものになるだろう:

//"May not work" example, do no use this 
glyphIndex = withUnsafePointer(to: &idRangeOffset[i]) {idRangeOffsetPointer in 
//In some cases `idRangeOffsetPointer` can work as `&idRangeOffset[i]` in C... 
    (idRangeOffsetPointer + Int(rangeOffset)/2 + Int(charCode - start)).pointee 
    //To make pointer operation in Swift, all integers need to be `Int`, 
    //And to match the C-rule of integer operation, you need to cast each portion to `Int` before adding operation 
    //The equivalent to C's dereferencing operator `*` in Swift is `pointee` property 
} 

しかし、これは、コピーイン/コピーアウトセマンティクスの期待通りに動作しない場合がありますSwiftのinoutパラメータの。 Swiftは、単一の要素idRangeOffset[i]を含む時間領域を作成し、そのアドレスをidRangeOffsetPointerに渡すことができるので、ポインタ操作の結果は時間領域の近くを指している可能性があります。

ポインタ操作から意味のある結果を得るには、配列のすべての要素が連続した領域に配置されることが保証されているコンテキストで作業する必要があります。

そしてまた、あなたはそのC-声明を知っている必要がありますする必要があります

glyphIndex = *(&idRangeOffset[i] + idRangeOffset[i]/2 + (c - startCode[i])) 

は事実に基づいている、その全体idRangeOffsetglyphIdArrayは、任意のギャップやパディングなしに連続した領域に配置されています。 (私はあなたがフォーマット4についてよく知っていると仮定します)idRangeOffsetには​​要素しか含まれていないので、次のコードは機能しません。

//"Should work" in a certain condition 
glyphIndex = idRangeOffset.withUnsafeBufferPointer{idRangeOffsetBufferPointer in 
    let idRangeOffsetPointer = idRangeOffsetBufferPointer.baseAddress! + i 
    //`idRangeOffsetPointer` is equivalent to `&idRangeOffset[i]` in C inside this closure 
    return (idRangeOffsetPointer + Int(rangeOffset)/2 + Int(charCode - start)).pointee 
} 

しかし、Cでのポインタと配列のセマンティクスを考慮すると、上記のコードは、これに相当します

glyphIndex = idRangeOffset[i + Int(rangeOffset)/2 + Int(charCode - start)] 

//`*(&arr[i] + n)` is equivalent to `arr[i + n]` in C 

私は繰り返し、idRangeOffsetとglyphIdArrayの全体の内容が含まれている必要がありidRangeOffsetアレイ。

+0

さて、私たちはもっと近づいているように感じます。私が質問を投稿する前に、 'withUnsafeBufferPointer'技術を試しましたが、役に立たなかった。しかし、 'idRangeOffset'の内容の最後に' glyphIndexArray'の内容を含める必要があるので、長い連続した配列になっていますか?これにより、基礎となるストレージをヒープなどのメモリのまとまった単位として格納できますか?私の無知のために私を許しなさい;私のSwift <=> Cのゲームは私がそれが欲しいと思っているほどシャープではありません。 –

+0

_itの1つの長い連続配列?_ True。数十万の要素が含まれている可能性があります。 _これにより、基礎となるストレージをヒープ上のメモリのまとまりの単位として格納することができますか?厳密な意味で真実ではありませんが、**下付き文字**または**を使用してアクセスすると、 withUnsafeBufferPointer' **です。 OmniProgの答えが示唆しているように、バイナリ・データ形式では、内容の意味は絶対的な位置やオフセットに依存することがあります。私の答えがあなたがそこに正確に入るのを助けることを望む。 – OOPer

0

@OOPerが言ったことを追加するには、興味のあるcmapやサブタブ全体をメモリに読み込んで、Swiftでドキュメンテーションを参考にして作業することをお勧めします。例えば、https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.htmlを参照されたい。また、Cの実装を参考にすることもできますが、それは経験豊富なCプログラマーでなければ良い方法ではありません。Cには微妙な違いがあり、あなたを噛ませる可能性があります。 Cではポインタとオフセットの点でcmapを使うのが本当に便利です。 Swiftはポインタに優しいわけではないので、テーブルにオフセットを使用するほうがよいでしょう。マップのさまざまな部分をさまざまな型の値として解釈する際に問題が発生する可能性がありますが、少なくともポインターマジックを扱う必要はありません。

+0

アドバイスをいただきありがとうございます。私は実際には、 "Swift"のやり方で他のほとんどのテーブル(他のFormatサブテーブルを含む)のためにすべてをメモリにロードしようとしています。この愚かなCポインタのものは、今私を抱きしめている唯一のものです。フォーマット4の解析以外にも、私は本当に良いことを感じています。私が持っているテーブルはすべて、値の種類がきれいです。できるだけデータを読み込むのが怠惰です。本当にかわいいです。完全にあなたと同意します;私はあまりにも多くの微妙なことがありますあなたがそれを最高に言ったように、あまりにも多くのCを明確に操縦しようとします! –

関連する問題