1
# Copyright (C) 2007 Canonical Ltd
1
# Copyright (C) 2007, 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
50
51
# inner loops, we don't need to do that at all, as the reference only lasts for
51
52
# a very short time.
52
53
cdef extern from "Python.h":
54
ctypedef int Py_ssize_t
53
55
int PyList_Append(object lst, object item) except -1
54
56
void *PyList_GetItem_object_void "PyList_GET_ITEM" (object lst, int index)
55
57
int PyList_CheckExact(object)
59
61
char *PyString_AsString(object p)
60
62
char *PyString_AS_STRING_void "PyString_AS_STRING" (void *p)
61
63
object PyString_FromString(char *)
62
object PyString_FromStringAndSize(char *, int)
64
object PyString_FromStringAndSize(char *, Py_ssize_t)
63
65
int PyString_Size(object p)
64
66
int PyString_GET_SIZE_void "PyString_GET_SIZE" (void *p)
65
67
int PyString_CheckExact(object p)
111
113
return <char*>found - <char*>_s
115
cdef object safe_string_from_size(char *s, Py_ssize_t size):
117
raise AssertionError(
118
'tried to create a string with an invalid size: %d @0x%x'
120
return PyString_FromStringAndSize(s, size)
114
123
cdef int _is_aligned(void *ptr):
115
124
"""Is this pointer aligned to an integer size offset?
470
479
cdef class Reader:
471
480
"""Maintain the current location, and return fields as you parse them."""
482
cdef object state # The DirState object
473
483
cdef object text # The overall string object
474
484
cdef char *text_cstr # Pointer to the beginning of text
475
485
cdef int text_size # Length of text
478
488
cdef char *cur_cstr # Pointer to the current record
479
489
cdef char *next # Pointer to the end of this record
481
def __init__(self, text):
491
def __init__(self, text, state):
483
494
self.text_cstr = PyString_AsString(text)
484
495
self.text_size = PyString_Size(text)
485
496
self.end_cstr = self.text_cstr + self.text_size
486
497
self.cur_cstr = self.text_cstr
488
cdef char *get_next(self, int *size):
499
cdef char *get_next(self, int *size) except NULL:
489
500
"""Return a pointer to the start of the next field."""
502
cdef Py_ssize_t extra_len
504
if self.cur_cstr == NULL:
505
raise AssertionError('get_next() called when cur_str is NULL')
506
elif self.cur_cstr >= self.end_cstr:
507
raise AssertionError('get_next() called when there are no chars'
491
509
next = self.cur_cstr
492
self.cur_cstr = <char*>memchr(next, c'\0', self.end_cstr-next)
510
self.cur_cstr = <char*>memchr(next, c'\0', self.end_cstr - next)
511
if self.cur_cstr == NULL:
512
extra_len = self.end_cstr - next
513
raise errors.DirstateCorrupt(self.state,
514
'failed to find trailing NULL (\\0).'
515
' Trailing garbage: %r'
516
% safe_string_from_size(next, extra_len))
493
517
size[0] = self.cur_cstr - next
494
518
self.cur_cstr = self.cur_cstr + 1
501
525
next = self.get_next(&size)
502
return PyString_FromStringAndSize(next, size)
526
return safe_string_from_size(next, size)
504
528
cdef int _init(self) except -1:
505
529
"""Get the pointer ready.
571
595
PyString_AS_STRING_void(p_current_dirname[0]),
572
596
cur_size+1) != 0):
573
dirname = PyString_FromStringAndSize(dirname_cstr, cur_size)
597
dirname = safe_string_from_size(dirname_cstr, cur_size)
574
598
p_current_dirname[0] = <void*>dirname
622
646
trailing = self.get_next(&cur_size)
623
647
if cur_size != 1 or trailing[0] != c'\n':
624
raise AssertionError(
648
raise errors.DirstateCorrupt(self.state,
625
649
'Bad parse, we expected to end on \\n, not: %d %s: %s'
626
% (cur_size, PyString_FromStringAndSize(trailing, cur_size),
650
% (cur_size, safe_string_from_size(trailing, cur_size),
630
def _parse_dirblocks(self, state):
654
def _parse_dirblocks(self):
631
655
"""Parse all dirblocks in the state file."""
632
656
cdef int num_trees
633
657
cdef object current_block
637
661
cdef int expected_entry_count
638
662
cdef int entry_count
640
num_trees = state._num_present_parents() + 1
641
expected_entry_count = state._num_entries
664
num_trees = self.state._num_present_parents() + 1
665
expected_entry_count = self.state._num_entries
643
667
# Ignore the first record
646
670
current_block = []
647
state._dirblocks = [('', current_block), ('', [])]
671
dirblocks = [('', current_block), ('', [])]
672
self.state._dirblocks = dirblocks
649
674
current_dirname = <void*>obj
663
688
# new block - different dirname
664
689
current_block = []
665
PyList_Append(state._dirblocks,
690
PyList_Append(dirblocks,
666
691
(<object>current_dirname, current_block))
667
692
PyList_Append(current_block, entry)
668
693
entry_count = entry_count + 1
669
694
if entry_count != expected_entry_count:
670
raise AssertionError('We read the wrong number of entries.'
695
raise errors.DirstateCorrupt(self.state,
696
'We read the wrong number of entries.'
671
697
' We expected to read %s, but read %s'
672
698
% (expected_entry_count, entry_count))
673
state._split_root_dirblock_into_contents()
699
self.state._split_root_dirblock_into_contents()
676
702
def _read_dirblocks_c(state):
689
715
text = state._state_file.read()
690
716
# TODO: check the crc checksums. crc_measured = zlib.crc32(text)
692
reader = Reader(text)
718
reader = Reader(text, state)
694
reader._parse_dirblocks(state)
720
reader._parse_dirblocks()
695
721
state._dirblock_state = DirState.IN_MEMORY_UNMODIFIED