1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Generic I/O interface implementation: memory buffer-based I/O.
9 : */
10 : #include "native_client/src/include/portability.h"
11 :
12 : #include <string.h>
13 : #include <errno.h>
14 :
15 : #include "native_client/src/shared/gio/gio.h"
16 :
17 : /*
18 : * Memory file is just read/write from/to an in-memory buffer. Once
19 : * the buffer is consumed, there is no refilling/flushing.
20 : */
21 :
22 : #if !defined(SIZE_T_MAX)
23 : # define SIZE_T_MAX ((size_t) -1)
24 : #endif
25 :
26 : struct GioVtbl const kGioMemoryFileVtbl = {
27 : GioMemoryFileDtor,
28 : GioMemoryFileRead,
29 : GioMemoryFileWrite,
30 : GioMemoryFileSeek,
31 : GioMemoryFileFlush,
32 : GioMemoryFileClose,
33 : };
34 :
35 :
36 : int GioMemoryFileCtor(struct GioMemoryFile *self,
37 : char *buffer,
38 1 : size_t len) {
39 1 : self->buffer = buffer;
40 1 : self->len = len;
41 1 : self->curpos = 0;
42 :
43 1 : self->base.vtbl = &kGioMemoryFileVtbl;
44 1 : return 1;
45 1 : }
46 :
47 :
48 : ssize_t GioMemoryFileRead(struct Gio *vself,
49 : void *buf,
50 1 : size_t count) {
51 1 : struct GioMemoryFile *self = (struct GioMemoryFile *) vself;
52 : size_t remain;
53 : size_t newpos;
54 :
55 : /* 0 <= self->curpos && self->curpos <= self->len */
56 1 : remain = self->len - self->curpos;
57 : /* 0 <= remain <= self->len */
58 1 : if (count > remain) {
59 1 : count = remain;
60 : }
61 : /* 0 <= count && count <= remain */
62 1 : if (0 == count) {
63 1 : return 0;
64 : }
65 1 : newpos = self->curpos + count;
66 : /* self->curpos <= newpos && newpos <= self->len */
67 :
68 1 : memcpy(buf, self->buffer + self->curpos, count);
69 1 : self->curpos = newpos;
70 1 : return count;
71 1 : }
72 :
73 :
74 : ssize_t GioMemoryFileWrite(struct Gio *vself,
75 : const void *buf,
76 1 : size_t count) {
77 1 : struct GioMemoryFile *self = (struct GioMemoryFile *) vself;
78 : size_t remain;
79 : size_t newpos;
80 :
81 : /* 0 <= self->curpos && self->curpos <= self->len */
82 1 : remain = self->len - self->curpos;
83 : /* 0 <= remain <= self->len */
84 1 : if (count > remain) {
85 1 : count = remain;
86 : }
87 : /* 0 <= count && count <= remain */
88 1 : if (0 == count) {
89 1 : return 0;
90 : }
91 1 : newpos = self->curpos + count;
92 : /* self->curpos <= newpos && newpos <= self->len */
93 :
94 1 : memcpy(self->buffer + self->curpos, buf, count);
95 1 : self->curpos = newpos;
96 : /* we never extend a memory file */
97 1 : return count;
98 1 : }
99 :
100 :
101 : off_t GioMemoryFileSeek(struct Gio *vself,
102 : off_t offset,
103 1 : int whence) {
104 1 : struct GioMemoryFile *self = (struct GioMemoryFile *) vself;
105 1 : size_t new_pos = (size_t) -1;
106 :
107 1 : switch (whence) {
108 : case SEEK_SET:
109 1 : new_pos = offset;
110 1 : break;
111 : case SEEK_CUR:
112 1 : new_pos = self->curpos + offset;
113 1 : break;
114 : case SEEK_END:
115 1 : new_pos = (size_t) (self->len + offset);
116 1 : break;
117 : default:
118 1 : errno = EINVAL;
119 : break;
120 : }
121 : /**
122 : * on error, new_pos should be SIZE_T_MAX. On overflow it will either
123 : * be greater than self->len, or will have wrapped around.
124 : * TODO (ilewis): Detect wraparound and return an error.
125 : */
126 1 : if (new_pos > self->len) {
127 1 : errno = EINVAL;
128 1 : return (off_t) -1;
129 : }
130 1 : self->curpos = new_pos;
131 1 : return (off_t) new_pos;
132 1 : }
133 :
134 :
135 1 : int GioMemoryFileClose(struct Gio *vself) {
136 : UNREFERENCED_PARAMETER(vself);
137 1 : return 0;
138 1 : }
139 :
140 :
141 1 : int GioMemoryFileFlush(struct Gio *vself) {
142 : UNREFERENCED_PARAMETER(vself);
143 1 : return 0;
144 1 : }
145 :
146 :
147 1 : void GioMemoryFileDtor(struct Gio *vself) {
148 : UNREFERENCED_PARAMETER(vself);
149 : return;
150 1 : }
|