Как этот CGPDFDictionaryGetString переводить в Monotouch? - PullRequest
2 голосов
/ 22 сентября 2011

У меня есть фрагмент кода ObjC от великолепного VFR PDF Viewer на GIT. Он использует CGPDFDictionaryGetString для получения указателя на строку из аннотации PDF. Затем он использует преобразование байтового указателя для получения окончательной строки. В Monotouch нет CGPDFDictionary.GetString(), а только .GetName() - это единственный метод, который возвращает строку, поэтому я предположил, что это должен быть правильный метод, но он не работает. Я могу получить массивы, словари, числа с плавающей запятой и целые числа просто отлично - кажется, что только строки не работают.

См. Примеры небольших кодов ниже.

CGPDFStringRef uriString = NULL;
// This returns TRUE in the ObjC version and uriString is a valid pointer to a string.
if (CGPDFDictionaryGetString(actionDictionary, "URI", &uriString) == true)
{
  // Do some pointer magic - how to do this in MT? Do I have to at all?
  const char *uri = (const char *)CGPDFStringGetBytePtr(uriString);
  // *uri now contains a URL, I can see it in the debugger.
}

Я перевел это так:

string sUri = null;
// This returns FALSE. Hence my sUri is NULL. Seems like GetName() is not the analogy to CGPDFDictionaryGetString.
if(oActionDic.GetName("URI", out sUri))
{
  // I never get here.
}

EDIT: Глядя на источники Mono, я вижу это в ветке Master: // TODO: GetString -> возвращает CGPDFString

Переключение на ветку 4.2 показывает, что она, кажется, там есть. Поэтому я скопировал код оттуда, но у меня есть две проблемы:

  • Я получаю сообщение об ошибке с ключевым словом unsafe. Он говорит мне, чтобы добавить «небезопасный» параметр командной строки. Что это такое и стоит ли добавлять это? Где?
  • Кажется, что все равно работает, но приложение зависает при получении CGPDFString.

[DllImport (Constants.CoreGraphicsLibrary)] public extern static IntPtr CGPDFStringGetLength (IntPtr pdfStr);

    [DllImport (Constants.CoreGraphicsLibrary)]
    public extern static IntPtr CGPDFStringGetBytePtr (IntPtr pdfStr);

    public static string PdfStringToString (IntPtr pdfString)
    {
        if (pdfString == IntPtr.Zero)
            return null;

        int n = (int)CGPDFStringGetLength (pdfString);
        unsafe
        {
            return new String ((char *)CGPDFStringGetBytePtr (pdfString), 0, n);
        }
    }

    [DllImport (Constants.CoreGraphicsLibrary)]
    extern static bool CGPDFDictionaryGetString (IntPtr handle, string key, out IntPtr result);

    public static bool GetStringFromPdfDictionary (CGPDFDictionary oPdfDic, string key, out string result)
    {
        if (key == null)
            throw new ArgumentNullException ("key");
        IntPtr res;
        if (CGPDFDictionaryGetString (oPdfDic.Handle, key, out res))
        {
            result = PdfStringToString (res);
            return true;
        }
        result = null;
        return false;
    }

Ответы [ 2 ]

1 голос
/ 22 сентября 2011

Если вы используете ключевое слово unsafe в своем источнике, вам нужно включить unsafe при сборке сборки.В MonoDevelop вы можете сделать это:

  • Щелкните правой кнопкой мыши на проекте;
  • Выберите Параметры меню;
  • Выберите Общие значок;
  • Нажмите Разрешить «небезопасный» код флажок
  • Нажмите ОК Кнопка
  • Затем восстановите.

Примечание. Ваша предыдущая сборка не работала бы без этого.

Исходный код между master и monotouch-4.2 должен быть идентиченв этом случае.Я проверю, но, вероятно, вы просматривали конкретную ревизию в GIT (она была передана до обновления кода).Я обязательно проверю и отредактирую сообщение.

ОБНОВЛЕНИЕ : Это ссылка на master (т.е. последний доступный код), и она показывает:

public bool GetString (string key, out string result)

будет доступно.Однако это зависит от небезопасного кода (внутри PdfStringToString), который вы не смогли бы скомпилировать без разрешения небезопасного кода в сборке, в которую вы скопировали / вставили этот код.

UPDATE2 : Возвращаемое значение кодируется в кодировке UTF8, поэтому созданная из него строка должна быть правильно декодирована (другой конструктор System.String позволяет это).Приведенная выше ссылка на master должна указывать на фиксированную версию.

0 голосов
/ 27 сентября 2011

Я не большой поклонник использования небезопасных блоков и разработал способ реализации этого метода без его использования.Изначально я попробовал небезопасный стиль, однако, поскольку строка хранится в UTF8, ее необходимо преобразовать.

private bool PDFDictionaryGetString (IntPtr handle, string key, out string result)
{
    IntPtr stringPtr;
    result = null;

    if (CGPDFDictionaryGetString(handle, "URI", out stringPtr)) {

        if (stringPtr == IntPtr.Zero)
                return false;

        // Get length of PDF String
        uint n = (uint) CGPDFStringGetLength (stringPtr);

        // Get the pointer of the string
        var ptr = CGPDFStringGetBytePtr (stringPtr);
        // Get the bytes
        var data = NSData.FromBytes(ptr, n);
        // Convert to UTF8
        var value = NSString.FromData(data, NSStringEncoding.UTF8);

        result = value.ToString();
        return true;
    }
    return false;
} 

Здесь есть полная запись в блоге здесь и рабочий образец, включая полный исходный код здесь с многостраничной навигацией и щелкающими ссылками.

...