C function substr, PHP extension, strncpy wrong length - php

My php_substr function should set kpart to a33c5b4b58b26d9f however it instead sets it to a33c5b4b58b26d9fìÿ?꬯wÿÿÿÿ®w.
Any ideas?
long ks;
char *kpart1;
ks = 16;
php_substr("a33c5b4b58b26d9f78293df1c5d5a3bf", &kpart1, 0, ks); // a33c5b4b58b26d9fìÿ?꬯wÿÿÿÿ®w
char *php_substr(char *str, char **ptr, long f, long l)
{
int str_len = strlen(str);
if (!l) {
l=0;
}
if (l!=0) {
if ((l < 0 && -l > str_len)) {
return FALSE;
} else if (l > str_len) {
l = str_len;
}
} else {
l = str_len;
}
if (f > str_len) {
return FALSE;
} else if (f < 0 && -f > str_len) {
f = 0;
}
if (l < 0 && (l + str_len - f) < 0) {
return FALSE;
}
if (f < 0) {
f = str_len + f;
if (f < 0) {
f = 0;
}
}
if (l < 0) {
l = (str_len - f) + l;
if (l < 0) {
l = 0;
}
}
if (f >= str_len) {
return FALSE;
}
if ((f + l) > str_len) {
l = str_len - f;
}
strncpy(*ptr,str+f,l);
return 0;
}
Edited to use malloc and included full working code!
I tried the zend engine emalloc however this didn't seem to work
long ks;
char *kpart1;
ks = 16;
kpart1 = php_substr("a33c5b4b58b26d9f78293df1c5d5a3bf", 0, ks); // a33c5b4b58b26d9f
char *php_substr(char *str, long f, long l)
{
int str_len = strlen(str);
unsigned char *buffer;
if (l!=0) {
if ((l < 0 && -l > str_len)) {
return FALSE;
} else if (l > str_len) {
l = str_len;
}
} else {
l = str_len;
}
if (f > str_len) {
return FALSE;
} else if (f < 0 && -f > str_len) {
f = 0;
}
if (l < 0 && (l + str_len - f) < 0) {
return FALSE;
}
if (f < 0) {
f = str_len + f;
if (f < 0) {
f = 0;
}
}
if (l < 0) {
l = (str_len - f) + l;
if (l < 0) {
l = 0;
}
}
if (f >= str_len) {
return FALSE;
}
if ((f + l) > str_len) {
l = str_len - f;
}
buffer = (char*)malloc(l+1);
strncpy(buffer,str+f,l);
buffer[l]='\0';
return buffer;
}

After trimming out all the testing of the parameters
After editing into a file that compiles/links/runs
this is the resulting code:
#include <stdio.h>
#include <string.h>
#define FALSE (0)
char *php_substr(char *str, char **ptr, long f, long l)
{
strncpy(*ptr,str+f,(size_t)l);
return 0;
}
int main( void )
{
long int ks = 16;
char *kpart1;
php_substr("a33c5b4b58b26d9f78293df1c5d5a3bf", &kpart1, 0, ks); // a33c5b4b58b26d9fìÿ?꬯wÿÿÿÿ®w
printf( "%s\n", kpart1);
}
Notice that the char pointer: kpart1 is not initialized to point to any specific location.
(in this case it contains whatever trash was on the stack. If it were a global variable, it would contian NULL.)
The call to strncpy() is trying to copy the first 16 bytes of the passed in constant to where ever kpart1 happens to be pointing.
The strncpy() results in undefined behaviour and can lead to a seg fault event.
I did not perform an analysis on the manipulation of the passed in variables f and l.
Suggest, as you found, that the pointer: kpart1 needs to be initialized to point to some allocated memory, where that allocated memory needs to be at least l-f+1 in length.

Related

How do I call go-code with a cmd command in PHP?

I have a .go code that I want to run and get the return value in PHP.
The line I use in CMD is "go run test.go map.csv" and I want to run it through a PHP script and get whatever the code returns on my website.
Right now I don't get anything to my variable in the PHP-code.
GO-code
package main
import (
"bytes"
"encoding/csv"
"fmt"
"io"
"log"
"math/bits"
"math/rand"
"os"
"runtime"
"strconv"
"strings"
"time"
)
const MaxInt = int(^uint(0) >> 1)
// IntSet
type IntSet struct {
Storage uint
}
func (vs IntSet) Contains(value int) bool {
return (vs.Storage & (1 << uint(value))) != 0
}
func (vs IntSet) Count() int {
return bits.OnesCount(vs.Storage)
}
func (vs *IntSet) Insert(value int) {
vs.Storage |= 1 << uint(value)
}
func (vs *IntSet) Remove(value int) {
vs.Storage &= ^(1 << uint(value))
}
func (vs IntSet) Value() int {
return int(vs.Storage >> 1)
}
func (vs IntSet) Iter() []int {
n := vs.Count()
v := make([]int, n)
for c, i := 0, 0; c < n; i++ {
if vs.Contains(i) {
v[c] = i
c++
}
}
return v
}
func (vs IntSet) String() string {
buf := bytes.Buffer{}
buf.WriteString("{")
delim := ""
for c, i := 0, 0; c < vs.Count(); i++ {
if vs.Contains(i) {
buf.WriteString(fmt.Sprintf("%s%v", delim, i))
delim = ","
c++
}
}
buf.WriteString("}")
return buf.String()
}
// Combinations 'k' integers from a serie '1..n'
type Combs []IntSet
func combWithLen(n, k, first int, vs IntSet, acc Combs) Combs {
if k > vs.Count() {
for x := first; x <= n; x++ {
s := vs
s.Insert(x)
acc = combWithLen(n, k, x+1, s, acc)
}
} else {
acc = append(acc, vs)
}
return acc
}
func Comb(n, k int) Combs {
return combWithLen(n, k, 1, IntSet{}, Combs{})
}
// Held Karp
type Path struct {
Cost int
From int
}
func minPath(paths []Path) Path {
m := paths[0]
for i := 1; i < len(paths); i++ {
if m.Cost > paths[i].Cost {
m = paths[i]
}
}
return m
}
func pathFromTo(from, to int, c [][]Path, dists CostMatrix, prev IntSet) Path {
p := Path{}
p.Cost = c[prev.Value()][from-1].Cost + dists[from][to]
p.From = from
return p
}
func reverse(a []int) []int {
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
return a
}
// CostMatrix
type CostMatrix [][]int
func (dists CostMatrix) CalcCostToSubsets(c [][]Path, edges, subsetSz int) {
maxWorkers := runtime.NumCPU()
workers := 0
done := make(chan bool)
for _, visited := range Comb(edges, subsetSz) {
if workers == maxWorkers {
<-done
} else {
workers += 1
}
go func(vs IntSet) {
subset := vs.Iter()
// Find the lowest cost to get to this subset
for _, k := range subset {
prev := vs
prev.Remove(k)
res := []Path{}
for _, m := range subset {
if m != k {
res = append(res, pathFromTo(m, k, c, dists, prev))
}
}
if len(res) > 0 {
c[vs.Value()][k-1] = minPath(res)
}
}
done <- true
}(visited)
}
// Wait for all workers to finish
for ; workers > 0; workers -= 1 {
<-done
}
}
func (dists CostMatrix) ShortestPath() (int, []int) {
n := len(dists)
c := make([][]Path, 1<<uint(n-1))
for i := 0; i < len(c); i++ {
c[i] = make([]Path, n-1)
}
// Add paths from start to first steps
for k := 1; k < n; k++ {
c[1<<uint(k-1)][k-1] = Path{dists[0][k], 0}
}
for s := 2; s < n; s++ {
dists.CalcCostToSubsets(c, n-1, s)
}
visited := IntSet{}
for k := 1; k < n; k++ {
visited.Insert(k)
}
// Add path back to start and calculate optimal cost
res := []Path{}
for k := 1; k < n; k++ {
res = append(res, pathFromTo(k, 0, c, dists, visited))
}
p := minPath(res)
cost := p.Cost
// Backtrack to find path
steps := make([]int, n+1)
for i := 1; i < n; i++ {
steps[i] = p.From
from := p.From
p = c[visited.Value()][p.From-1]
visited.Remove(from)
}
return cost, reverse(steps)
}
func (c CostMatrix) MaxDigitWidth() (width int) {
for row := 0; row < len(c); row++ {
for col := 0; col < len(c[row]); col++ {
w := 0
for d := c[row][col]; d > 0; d /= 10 {
w += 1
}
if width < w {
width = w
}
}
}
return
}
func (c CostMatrix) String() string {
fmtstr := fmt.Sprintf("%%%vv", c.MaxDigitWidth())
buf := bytes.Buffer{}
for row := 0; row < len(c); row++ {
if row == 0 {
buf.WriteString("{\n")
}
buf.WriteString(" { ")
for col := 0; col < len(c[row]); col++ {
buf.WriteString(fmt.Sprintf(fmtstr, c[row][col]))
if col != len(c[row])-1 {
buf.WriteString(", ")
}
}
buf.WriteString(" },\n")
if row == len(c)-1 {
buf.WriteString("}")
} else {
}
}
return buf.String()
}
func Abs(n int) int {
if n < 0 {
return -n
}
return n
}
func Max(a, b int) int {
if a < b {
return b
}
return a
}
type Location struct {
shelf int
level int
}
func cost(from, to Location) int {
dx := Abs(from.shelf - to.shelf)
dy := Abs(from.level-to.level) * 2
return Max(dx, dy)
}
func zeroMatrix(dim int) CostMatrix {
var c CostMatrix = make([][]int, dim)
for i := range c {
c[i] = make([]int, dim)
}
return c
}
func genMatrix(nodes, depth, height int) CostMatrix {
rand.Seed(time.Now().UnixNano())
c := zeroMatrix(nodes)
l := make([]Location, nodes)
for i := range l {
l[i] = Location{rand.Intn(depth), rand.Intn(height)}
}
for row := 0; row < nodes; row++ {
for col := row + 1; col < nodes; col++ {
c[row][col] = cost(l[row], l[col])
c[col][row] = c[row][col]
}
}
return c
}
func readMatrix(r io.Reader) CostMatrix {
cr := csv.NewReader(r)
rec, err := cr.ReadAll()
if err != nil {
log.Fatalln(err)
}
M := zeroMatrix(len(rec))
for row, line := range rec {
for col, str := range line {
v, err := strconv.ParseInt(strings.TrimSpace(str), 10, 32)
if err != nil {
log.Fatalln(err)
}
M[row][col] = int(v)
}
}
return M
}
func GetCostMatrix() CostMatrix {
if len(os.Args) == 1 {
return readMatrix(os.Stdin)
}
arg := os.Args[1]
if strings.HasSuffix(arg, ".csv") {
file, err := os.Open(arg)
if err != nil {
log.Fatalln(err)
}
return readMatrix(file)
}
dim, err := strconv.ParseInt(arg, 10, 32)
if err != nil {
log.Fatalln(err)
}
return genMatrix(int(dim), 50, 9)
}
// Program entrypoint
func main() {
start := time.Now()
time.Sleep(time.Second * 2)
c := GetCostMatrix()
fmt.Println(c)
fmt.Println(c.ShortestPath())
elapsed := time.Since(start)
fmt.Printf("Processen tog %s sekunder", elapsed)
}
I want to catch what the GO-code main() returns in PHP:
<?php
$cmdOutput = exec('go run c:/Go/src/hello/test.go c:/Go/src/hello/map.csv');
var_dump($cmdOutput);
?>
but it says $cmdOutput is 0.
To capture the output, you need to provide extra parameters.
$cmdOutput = []; // Variabled passed by reference.
exec('go run c:/Go/src/hello/test.go c:/Go/src/hello/map.csv', $cmdOutput);
var_dump($cmdOutput); // Will be an array of all printed lines.
documentation exec function
$cmd = '/usr/local/go/bin/go /path/to/test.go map.csv 2>&1';
exec($cmd, $output, $return_var);
var_dump($output);
just make sure your web server user has permissions (e.g www-data).

auto-increment alphanumeric php , javascript

I want to make an auto-increment alphanumeric and this is just for output
if i press a button , there is an output AA001 and then i press a button again there is an output AA002
This doesn't use any 'clever' tricks but is shorter and easier to understand and tweak. It also uses numbers so it doesn't grow the length of the string as quickly. It increments from 0-9 then a-z, but it is intended that you should feed in 'a' to start with. Output always starts with an alphabet character, as long as your input also starts with an alphabet character, so it can be used as PHP variable names
var nextVarName = function(str) {
// Position of char to change.
var change = str.length - 1;
// The value of that char.
var change_char = str[change];
// Number of zeros to append when flipping.
var zeros = 0;
// Iterate backwards while there's a z (flipping).
while (change_char == 'z') {
// Increase the length of appended zeros
zeros++;
// Move the char to change back.
change_char = str[--change];
}
if (change_char == undefined) {
// Full flip - string increases in length.
str = 'a' + Array(str.length + 1).join("0");
} else {
// Normal increment with partial flip and 9->a handling.
str = str.substr(0, change)
+ (change_char == '9' ? 'a' : String.fromCharCode(str.charCodeAt(change) + 1))
+ Array(zeros + 1).join('0');
}
return str;
};
var vname = 'a';
for (var i = 0; i < 5; i++) {
vname = nextVarName(vname);
console.log(vname);
}
The results will be as follows:
z ---> a0
9z ---> a0 (unexpected input)
ab1zde ---> ab1zdf
abcdzz ---> abce00
zzzzz ---> a00000
abcyzz ---> abcz00
9000 ---> 9001 (unexpected input)
https://jsfiddle.net/e20kfvky/
The schedule of how many variables (that start with an alphabet char) are created of each length is as follows:
1: 26, 2: 936, 3: 33696, 4: 1213056 ... n: 36 ^ n - 10 * 36 ^ (n - 1)
The following code will generate a token that you can advance by one. It uses some small classes to make it modular. The function you attach to the button will call the function next on the token as shown in the very bottom.
//Element in a big token
function Increment(startval, endval) {
this.start = startval.charCodeAt(0);
this.cur = this.start;
this.end = endval.charCodeAt(0);
//Returns the current value
this.get = function() {
if (this.cur <= this.end) {
return String.fromCharCode(this.cur);
} else {
return null;
}
}
//Advances the value we will show
this.next = function() {
this.cur += 1;
return this.get();
}
//Reset it to the beginning
this.reset = function() {
this.cur = this.start;
}
}
function Token() {
this.token = [
new Increment("A", "Z"),
new Increment("A", "Z"),
new Increment("0", "9"),
new Increment("0", "9"),
new Increment("0", "9")
];
this.get = function() {
return this.token.map(function(cur) {
return cur.get();
}).join("");
}
this.next = function() {
//From the back to the front
for (var i = this.token.length - 1; i >= 0; i--) {
if (this.token[i].next() == null) {
//If we exhausted all possible values, continue
this.token[i].reset();
} else {
//Until we advance one that has still values left
break;
}
}
return this.get();
}
}
//Now we are just showing off...
var a = new Token();
for (var i = 0; i < 15; i++) {
console.log(a.next());
}
const getNextAlphaString = function (str) {
"use strict";
str=str.toUpperCase();
let chars;
chars = str.split("");
const strLen = str.length;
let continueIncermenting = true;
for (let i = strLen - 1; i >= 0; i = i - 1) {
let asciiVal;
asciiVal = chars[i].charCodeAt(0);
if (isNaN(asciiVal)) {
return str;
}
if (continueIncermenting === true) {
if (asciiVal >= 48 && asciiVal < 57) {
chars[i] = String.fromCharCode(asciiVal + 1);
continueIncermenting = false;
break;
} else if (asciiVal == 57) {
chars[i] = '0';
continueIncermenting = true;
}
if (asciiVal >= 65 && asciiVal < 90) {
chars[i] = String.fromCharCode(asciiVal + 1);
continueIncermenting = false;
break;
} else if (asciiVal == 90) {
chars[i] = String.fromCharCode(65);
continueIncermenting = true;
}
} else {
if (asciiVal == 90) {
continueIncermenting = true;
chars[i] = String.fromCharCode(65);
}
if (asciiVal == 57) {
continueIncermenting = true;
chars[i] = '0';
}
}
}
if (continueIncermenting === true) {
let firstAcii = chars[0].charCodeAt(0);
if (isNaN(firstAcii)) {
return str;
}
if ((firstAcii >= 65 && firstAcii <= 90) || (firstAcii >= 97 && firstAcii <= 122)) {
return 'A' + chars.join('').toUpperCase();
}
if (firstAcii >= 48 && firstAcii <= 57) {
return '0' + chars.join('').toUpperCase();
}
}
return chars.join('').toUpperCase();
};
The results will be as follows:
ab1zde ---> AB1ZDF
abcdzz ---> ABCEAA
zzzzz ---> AAAAAA
abcyzz ---> ABCZAA
9000 ---> 9001

How to see the source code / content of a built in function in PHP?

Is there an easy way in PHP to figure out the source code/content of a built in function?
Say for example I want to know what base64_decode() actually does to the given encoded base64 string to convert it to a plain text. How can I achieve this?
You can browse the source code of PHP here
In your case base64_decode is implemented here (PHP 5.6.0)
Note: This code is in C since that's what PHP is written in. In fact all built-in functions and extensions of PHP are written in C.
PHPAPI unsigned char *php_base64_decode_ex(const unsigned char *str, int length, int *ret_length, zend_bool strict) /* {{{ */
{
const unsigned char *current = str;
int ch, i = 0, j = 0, k;
/* this sucks for threaded environments */
unsigned char *result;
result = (unsigned char *)safe_emalloc(length, 1, 1);
/* run through the whole string, converting as we go */
while ((ch = *current++) != '\0' && length-- > 0) {
if (ch == base64_pad) {
if (*current != '=' && ((i % 4) == 1 || (strict && length > 0))) {
if ((i % 4) != 1) {
while (isspace(*(++current))) {
continue;
}
if (*current == '\0') {
continue;
}
}
efree(result);
return NULL;
}
continue;
}
ch = base64_reverse_table[ch];
if ((!strict && ch < 0) || ch == -1) { /* a space or some other separator character, we simply skip over */
continue;
} else if (ch == -2) {
efree(result);
return NULL;
}
switch(i % 4) {
case 0:
result[j] = ch << 2;
break;
case 1:
result[j++] |= ch >> 4;
result[j] = (ch & 0x0f) << 4;
break;
case 2:
result[j++] |= ch >>2;
result[j] = (ch & 0x03) << 6;
break;
case 3:
result[j++] |= ch;
break;
}
i++;
}
k = j;
/* mop things up if we ended on a boundary */
if (ch == base64_pad) {
switch(i % 4) {
case 1:
efree(result);
return NULL;
case 2:
k++;
case 3:
result[k] = 0;
}
}
if(ret_length) {
*ret_length = j;
}
result[j] = '\0';
return result;
}

Implementing python slice notation

I'm trying to reimplement python slice notation in another language (php) and looking for a snippet (in any language or pseudocode) that would mimic the python logic. That is, given a list and a triple (start, stop, step) or a part thereof, determine correct values or defaults for all parameters and return a slice as a new list.
I tried looking into the source. That code is far beyond my c skills, but I can't help but agree with the comment saying:
/* this is harder to get right than you might think */
Also, if something like this is already done, pointers will be greatly appreciated.
This is my test bench (make sure your code passes before posting):
#place your code below
code = """
def mySlice(L, start=None, stop=None, step=None):
or
<?php function mySlice($L, $start=NULL, $stop=NULL, $step=NULL) ...
or
function mySlice(L, start, stop, step) ...
"""
import itertools
L = [0,1,2,3,4,5,6,7,8,9]
if code.strip().startswith('<?php'):
mode = 'php'
if code.strip().startswith('def'):
mode = 'python'
if code.strip().startswith('function'):
mode = 'js'
if mode == 'php':
var, none = '$L', 'NULL'
print code, '\n'
print '$L=array(%s);' % ','.join(str(x) for x in L)
print "function _c($s,$a,$e){if($a!==$e)echo $s,' should be [',implode(',',$e),'] got [',implode(',',$a),']',PHP_EOL;}"
if mode == 'python':
var, none = 'L', 'None'
print code, '\n'
print 'L=%r' % L
print "def _c(s,a,e):\n\tif a!=e:\n\t\tprint s,'should be',e,'got',a"
if mode == 'js':
var, none = 'L', 'undefined'
print code, '\n'
print 'L=%r' % L
print "function _c(s,a,e){if(a.join()!==e.join())console.log(s+' should be ['+e.join()+'] got ['+a.join()+']');}"
print
n = len(L) + 3
start = range(-n, n) + [None, 100, -100]
stop = range(-n, n) + [None, 100, -100]
step = range(-n, n) + [100, -100]
for q in itertools.product(start, stop, step):
if not q[2]: q = q[:-1]
actual = 'mySlice(%s,%s)' % (var, ','.join(none if x is None else str(x) for x in q))
slice_ = 'L[%s]' % ':'.join('' if x is None else str(x) for x in q)
expect = eval(slice_)
if mode == 'php':
expect = 'array(%s)' % ','.join(str(x) for x in expect)
print "_c(%r,%s,%s);" % (slice_, actual, expect)
if mode == 'python':
print "_c(%r,%s,%s);" % (slice_, actual, expect)
if mode == 'js':
print "_c(%r,%s,%s);" % (slice_, actual, expect)
how to use it:
save into a file (test.py)
place your python, php or javascript code between """s
run python test.py | python or python test.py | php or python test.py | node
Here's a straight port of the C code:
def adjust_endpoint(length, endpoint, step):
if endpoint < 0:
endpoint += length
if endpoint < 0:
endpoint = -1 if step < 0 else 0
elif endpoint >= length:
endpoint = length - 1 if step < 0 else length
return endpoint
def adjust_slice(length, start, stop, step):
if step is None:
step = 1
elif step == 0:
raise ValueError("step cannot be 0")
if start is None:
start = length - 1 if step < 0 else 0
else:
start = adjust_endpoint(length, start, step)
if stop is None:
stop = -1 if step < 0 else length
else:
stop = adjust_endpoint(length, stop, step)
return start, stop, step
def slice_indices(length, start, stop, step):
start, stop, step = adjust_slice(length, start, stop, step)
i = start
while (i > stop) if step < 0 else (i < stop):
yield i
i += step
def mySlice(L, start=None, stop=None, step=None):
return [L[i] for i in slice_indices(len(L), start, stop, step)]
This is what I came up with (python)
def mySlice(L, start=None, stop=None, step=None):
answer = []
if not start:
start = 0
if start < 0:
start += len(L)
if not stop:
stop = len(L)
if stop < 0:
stop += len(L)
if not step:
step = 1
if stop == start or (stop<=start and step>0) or (stop>=start and step<0):
return []
i = start
while i != stop:
try:
answer.append(L[i])
i += step
except:
break
return answer
Seems to work - let me know what you think
Hope it helps
This is a solution I came up with in C# .NET, maybe not the prettiest, but it works.
private object[] Slice(object[] list, int start = 0, int stop = 0, int step = 0)
{
List<object> result = new List<object>();
if (step == 0) step = 1;
if (start < 0)
{
for (int i = list.Length + start; i < list.Length - (list.Length + start); i++)
{
result.Add(list[i]);
}
}
if (start >= 0 && stop == 0) stop = list.Length - (start >= 0 ? start : 0);
else if (start >= 0 && stop < 0) stop = list.Length + stop;
int loopStart = (start < 0 ? 0 : start);
int loopEnd = (start > 0 ? start + stop : stop);
if (step > 0)
{
for (int i = loopStart; i < loopEnd; i += step)
result.Add(list[i]);
}
else if (step < 0)
{
for (int i = loopEnd - 1; i >= loopStart; i += step)
result.Add(list[i]);
}
return result.ToArray();
}
I've written a PHP port based on the C code, optimized for step sizes -1 and 1:
function get_indices($length, $step, &$start, &$end, &$size)
{
if (is_null($start)) {
$start = $step < 0 ? $length - 1 : 0;
} else {
if ($start < 0) {
$start += $length;
if ($start < 0) {
$start = $step < 0 ? -1 : 0;
}
} elseif ($start >= $length) {
$start = $step < 0 ? $length - 1 : $length;
}
}
if (is_null($end)) {
$end = $step < 0 ? -1 : $length;
} else {
if ($end < 0) {
$end += $length;
if ($end < 0) {
$end = $step < 0 ? - 1 : 0;
}
} elseif ($end >= $length) {
$end = $step < 0 ? $length - 1 : $length;
}
}
if (($step < 0 && $end >= $start) || ($step > 0 && $start >= $end)) {
$size = 0;
} elseif ($step < 0) {
$size = ($end - $start + 1) / $step + 1;
} else {
$size = ($end - $start - 1) / $step + 1;
}
}
function mySlice($L, $start = NULL, $end = NULL, $step = 1)
{
if (!$step) {
return false; // could throw exception too
}
$length = count($L);
get_indices($length, $step, $start, $end, $size);
// optimize default step
if ($step == 1) {
// apply native array_slice()
return array_slice($L, $start, $size);
} elseif ($step == -1) {
// negative step needs an array reversal first
// with range translation
return array_slice(array_reverse($L), $length - $start - 1, $size);
} else {
// standard fallback
$r = array();
for ($i = $start; $step < 0 ? $i > $end : $i < $end; $i += $step) {
$r[] = $L[$i];
}
return $r;
}
}
This is based on #ecatmur's Python code ported again to PHP.
<?php
function adjust_endpoint($length, $endpoint, $step) {
if ($endpoint < 0) {
$endpoint += $length;
if ($endpoint < 0) {
$endpoint = $step < 0 ? -1 : 0;
}
}
elseif ($endpoint >= $length) {
$endpoint = $step < 0 ? $length - 1 : $length;
}
return $endpoint;
}
function mySlice($L, $start = null, $stop = null, $step = null) {
$sliced = array();
$length = count($L);
// adjust_slice()
if ($step === null) {
$step = 1;
}
elseif ($step == 0) {
throw new Exception('step cannot be 0');
}
if ($start === null) {
$start = $step < 0 ? $length - 1 : 0;
}
else {
$start = adjust_endpoint($length, $start, $step);
}
if ($stop === null) {
$stop = $step < 0 ? -1 : $length;
}
else {
$stop = adjust_endpoint($length, $stop, $step);
}
// slice_indices()
$i = $start;
$result = array();
while ($step < 0 ? ($i > $stop) : ($i < $stop)) {
$sliced []= $L[$i];
$i += $step;
}
return $sliced;
}
I can't say there's no bug in the codes, but it had past your test program :)
def mySlice(L, start=None, stop=None, step=None):
ret = []
le = len(L)
if step is None: step = 1
if step > 0: #this situation might be easier
if start is None:
start = 0
else:
if start < 0: start += le
if start < 0: start = 0
if start > le: start = le
if stop is None:
stop = le
else:
if stop < 0: stop += le
if stop < 0: stop = 0
if stop > le: stop = le
else:
if start is None:
start = le-1
else:
if start < 0: start += le
if start < 0: start = -1
if start >= le: start = le-1
if stop is None:
stop = -1 #stop is not 0 because we need L[0]
else:
if stop < 0: stop += le
if stop < 0: stop = -1
if stop >= le: stop = le
#(stop-start)*step>0 to make sure 2 things:
#1: step != 0
#2: iteration will end
while start != stop and (stop-start)*step > 0 and start >=0 and start < le:
ret.append( L[start] )
start += step
return ret

Converting a hexadecimal string into binary in Objective-C

What's an equivalent of the PHP function pack:
pack('H*', '01234567989abcdef' );
in Objective-C?
Assuming that you want the results as an NSData, you can use a function similar to this:
NSData *CreateDataWithHexString(NSString *inputString)
{
NSUInteger inLength = [inputString length];
unichar *inCharacters = alloca(sizeof(unichar) * inLength);
[inputString getCharacters:inCharacters range:NSMakeRange(0, inLength)];
UInt8 *outBytes = malloc(sizeof(UInt8) * ((inLength / 2) + 1));
NSInteger i, o = 0;
UInt8 outByte = 0;
for (i = 0; i < inLength; i++) {
UInt8 c = inCharacters[i];
SInt8 value = -1;
if (c >= '0' && c <= '9') value = (c - '0');
else if (c >= 'A' && c <= 'F') value = 10 + (c - 'A');
else if (c >= 'a' && c <= 'f') value = 10 + (c - 'a');
if (value >= 0) {
if (i % 2 == 1) {
outBytes[o++] = (outByte << 4) | value;
outByte = 0;
} else if (i == (inLength - 1)) {
outBytes[o++] = value << 4;
} else {
outByte = value;
}
} else {
if (o != 0) break;
}
}
return [[NSData alloc] initWithBytesNoCopy:outBytes length:o freeWhenDone:YES];
}
See the -scanHex... methods of NSScanner.

Categories