CPF/Source Code
From SimsWiki
Overview
This page contains a sample R function to read a CPF and extract information about it.
Use at your own risk. Any comments please use the Talk:CPF/Source Code page.
Source
# # raw is a list of bytes (raw format). They # should have been read by readBin(f, "raw", n) or # using a decompressing routine # # The return value is a list, with "human" as a human-readable # list of things in the CPF. # convert_cpf <- function(raw) { cpf <- NULL cpf$id <- "CPF" cpf$version <- get_little_endian(raw, 2) n <- get_little_endian(raw[3:6], 4) # number of entries cpf$data <- NULL pos <- 7 # first 6 bytes are version and number of fields # start decoding at position 7 for (i in 1:n) { xtype <- get_little_endian(raw[pos:(pos+3)], 4) # xtype is the type of the data, in a crazy hex code pos <- pos + 4 # after each interpretation of raw bytes, we should move pos nlen <- get_little_endian(raw[pos:(pos+3)], 4) # len of field name pos <- pos + 4 name <- rawToChar(raw[pos:(pos+nlen-1)]) pos <- pos + nlen if (xtype == 0xEB61E4F7 || xtype == 0x0C264712 || xtype == 0xABC78708) { # integer or float # Nota Bene: I didn't care for float data, I just read and ignore data <- get_little_endian(raw[pos:(pos+3)], 4) pos <- pos + 4 cpf[[name]] <- data } else if (xtype == 0x0B8BEA18) { # string # get string length slen <- get_little_endian(raw[pos:(pos+3)], 4) pos <- pos + 4 str <- rawToChar(raw[pos:(pos+slen-1)]) pos <- pos + slen cpf[[name]] <- str } else if (xtype == 0xCBA908E1) { # boolean cpf[[name]] <- raw[pos] pos <- pos + 1 } } return(cpf) } # # get_little_endian converts n bytes in little-endian # format. It means that the first byte is the less significant # get_little_endian <- function(bytes, n) { return(sum(256^(0:(n-1)) * as.integer(bytes[1:n]))) }